2016-07-07 11:47:58 +03:00
//--------------------------------------------------------------------*- 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"
2017-01-28 04:41:30 +03:00
# include "cling/Utils/Diagnostics.h"
2016-07-07 11:47:58 +03:00
2016-07-14 19:06:47 +03:00
# include "clang/AST/ASTContext.h"
2017-01-28 04:41:30 +03:00
# include "clang/AST/ASTDiagnostic.h"
2016-07-14 19:06:47 +03:00
# include "clang/AST/ASTImporter.h"
# include "clang/Frontend/CompilerInstance.h"
2016-07-07 11:47:58 +03:00
# include "clang/Lex/Preprocessor.h"
2016-07-14 19:06:47 +03:00
# include "clang/Sema/Sema.h"
2016-07-07 11:47:58 +03:00
using namespace clang ;
namespace {
class ClingASTImporter : public ASTImporter {
private :
cling : : ExternalInterpreterSource & m_Source ;
public :
ClingASTImporter ( ASTContext & ToContext , FileManager & ToFileManager ,
ASTContext & FromContext , FileManager & FromFileManager ,
2016-07-15 13:50:02 +03:00
bool MinimalImport ,
cling : : ExternalInterpreterSource & source ) :
2016-07-07 11:47:58 +03:00
ASTImporter ( ToContext , ToFileManager , FromContext , FromFileManager ,
MinimalImport ) , m_Source ( source ) { }
2016-07-14 19:06:47 +03:00
virtual ~ ClingASTImporter ( ) = default ;
2016-07-07 11:47:58 +03:00
2020-03-10 20:15:22 +03:00
void Imported ( Decl * From , Decl * To ) override {
2016-07-07 11:47:58 +03:00
ASTImporter : : Imported ( From , To ) ;
if ( clang : : TagDecl * toTagDecl = dyn_cast < TagDecl > ( To ) ) {
toTagDecl - > setHasExternalLexicalStorage ( ) ;
toTagDecl - > setMustBuildLookupTable ( ) ;
2016-07-14 19:06:47 +03:00
toTagDecl - > setHasExternalVisibleStorage ( ) ;
2016-07-07 11:47:58 +03:00
}
2016-07-14 19:06:47 +03:00
if ( NamespaceDecl * toNamespaceDecl = dyn_cast < NamespaceDecl > ( To ) ) {
toNamespaceDecl - > setHasExternalVisibleStorage ( ) ;
2016-07-07 11:47:58 +03:00
}
2016-07-14 19:06:47 +03:00
if ( ObjCContainerDecl * toContainerDecl = dyn_cast < ObjCContainerDecl > ( To ) ) {
toContainerDecl - > setHasExternalLexicalStorage ( ) ;
toContainerDecl - > setHasExternalVisibleStorage ( ) ;
2016-07-07 11:47:58 +03:00
}
// Put the name of the Decl imported with the
// DeclarationName coming from the parent, in my map.
2016-07-14 19:06:47 +03:00
if ( NamedDecl * toNamedDecl = llvm : : dyn_cast < NamedDecl > ( To ) ) {
2016-07-18 16:40:44 +03:00
NamedDecl * fromNamedDecl = llvm : : dyn_cast < NamedDecl > ( From ) ;
2016-07-07 11:47:58 +03:00
m_Source . addToImportedDecls ( toNamedDecl - > getDeclName ( ) ,
fromNamedDecl - > getDeclName ( ) ) ;
}
2016-07-14 19:06:47 +03:00
if ( DeclContext * toDeclContext = llvm : : dyn_cast < DeclContext > ( To ) ) {
2016-07-18 16:40:44 +03:00
DeclContext * fromDeclContext = llvm : : dyn_cast < DeclContext > ( From ) ;
2016-07-07 11:47:58 +03:00
m_Source . addToImportedDeclContexts ( toDeclContext , fromDeclContext ) ;
}
}
} ;
}
namespace cling {
ExternalInterpreterSource : : ExternalInterpreterSource (
2016-07-15 13:50:02 +03:00
const cling : : Interpreter * parent , cling : : Interpreter * child ) :
m_ParentInterpreter ( parent ) , m_ChildInterpreter ( child ) {
2016-07-07 11:47:58 +03:00
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 ;
2016-07-14 19:06:47 +03:00
2016-07-15 13:50:02 +03:00
FileManager & childFM = m_ChildInterpreter - > getCI ( ) - > getFileManager ( ) ;
FileManager & parentFM = m_ParentInterpreter - > getCI ( ) - > getFileManager ( ) ;
2016-07-07 11:47:58 +03:00
2016-07-15 13:50:02 +03:00
ASTContext & fromASTContext = m_ParentInterpreter - > getCI ( ) - > getASTContext ( ) ;
ASTContext & toASTContext = m_ChildInterpreter - > getCI ( ) - > getASTContext ( ) ;
ClingASTImporter * importer
= new ClingASTImporter ( toASTContext , childFM , fromASTContext , parentFM ,
/*MinimalImport : ON*/ true , * this ) ;
m_Importer . reset ( llvm : : dyn_cast < ASTImporter > ( importer ) ) ;
2016-07-07 11:47:58 +03:00
}
2016-07-15 13:50:02 +03:00
ExternalInterpreterSource : : ~ ExternalInterpreterSource ( ) { }
2016-07-07 11:47:58 +03:00
void ExternalInterpreterSource : : ImportDecl ( Decl * declToImport ,
DeclarationName & childDeclName ,
DeclarationName & parentDeclName ,
const DeclContext * childCurrentDeclContext ) {
2016-12-21 22:01:22 +03:00
// Don't do the import if we have a Function Template or using decls. They
// are not supported by clang.
// FIXME: These are temporary checks and should be de-activated once clang
// supports their import.
if ( ( declToImport - > isFunctionOrFunctionTemplate ( )
& & declToImport - > isTemplateDecl ( ) ) | | dyn_cast < UsingDecl > ( declToImport )
| | dyn_cast < UsingShadowDecl > ( declToImport ) ) {
# ifndef NDEBUG
2017-01-28 04:41:30 +03:00
utils : : DiagnosticsStore DS (
m_Importer - > getFromContext ( ) . getDiagnostics ( ) , false , false , true ) ;
2020-08-17 13:21:34 +03:00
const Decl * To = llvm : : cantFail ( m_Importer - > Import ( declToImport ) ) ;
assert ( To & & " Import did not work! " ) ;
assert ( ( DS . empty ( ) | |
2023-08-17 16:59:40 +03:00
DS [ 0 ] . getID ( ) ! = clang : : diag : : err_unsupported_ast_node ) & &
2020-08-17 13:21:34 +03:00
" Import not supported! " ) ;
2016-12-21 22:01:22 +03:00
# endif
2016-07-07 11:47:58 +03:00
return ;
2016-12-21 22:01:22 +03:00
}
2016-07-07 11:47:58 +03:00
2020-03-11 13:12:58 +03:00
if ( auto toOrErr = m_Importer - > Import ( declToImport ) ) {
if ( NamedDecl * importedNamedDecl = llvm : : dyn_cast < NamedDecl > ( * toOrErr ) ) {
2016-07-07 11:47:58 +03:00
SetExternalVisibleDeclsForName ( childCurrentDeclContext ,
importedNamedDecl - > getDeclName ( ) ,
2016-07-14 19:06:47 +03:00
importedNamedDecl ) ;
2016-07-07 11:47:58 +03:00
}
// Put the name of the Decl imported with the
// DeclarationName coming from the parent, in my map.
m_ImportedDecls [ childDeclName ] = parentDeclName ;
2020-03-11 13:12:58 +03:00
} else {
logAllUnhandledErrors ( toOrErr . takeError ( ) , llvm : : errs ( ) ,
" Error importing decl " ) ;
2016-07-07 11:47:58 +03:00
}
}
void ExternalInterpreterSource : : ImportDeclContext (
DeclContext * declContextToImport ,
DeclarationName & childDeclName ,
DeclarationName & parentDeclName ,
const DeclContext * childCurrentDeclContext ) {
2020-03-11 13:12:58 +03:00
if ( auto toOrErr = m_Importer - > ImportContext ( declContextToImport ) ) {
2016-07-07 11:47:58 +03:00
2020-03-11 13:12:58 +03:00
DeclContext * importedDC = * toOrErr ;
importedDC - > setHasExternalVisibleStorage ( true ) ;
if ( NamedDecl * importedND = llvm : : dyn_cast < NamedDecl > ( importedDC ) ) {
2016-07-07 11:47:58 +03:00
SetExternalVisibleDeclsForName ( childCurrentDeclContext ,
2020-03-11 13:12:58 +03:00
importedND - > getDeclName ( ) ,
importedND ) ;
2016-07-07 11:47:58 +03:00
}
// 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.
2020-03-11 13:12:58 +03:00
m_ImportedDeclContexts [ importedDC ] = declContextToImport ;
} else {
logAllUnhandledErrors ( toOrErr . takeError ( ) , llvm : : errs ( ) ,
" Error importing decl context " ) ;
2016-07-07 11:47:58 +03:00
}
}
bool ExternalInterpreterSource : : Import ( DeclContext : : lookup_result lookup_result ,
const DeclContext * childCurrentDeclContext ,
DeclarationName & childDeclName ,
DeclarationName & parentDeclName ) {
2016-07-15 13:50:02 +03:00
2016-07-07 11:47:58 +03:00
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 ) ) {
2016-07-15 13:50:02 +03:00
ImportDeclContext ( declContextToImport , childDeclName ,
2016-07-07 11:47:58 +03:00
parentDeclName , childCurrentDeclContext ) ;
}
2016-07-15 13:50:02 +03:00
ImportDecl ( * I , childDeclName , parentDeclName , childCurrentDeclContext ) ;
2016-07-07 11:47:58 +03:00
}
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 ( ) ) {
2016-07-15 13:50:02 +03:00
if ( Import ( lookup_result ,
2016-07-07 11:47:58 +03:00
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 ;
// 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 ( ) ;
2024-02-02 13:11:47 +03:00
if ( ! name . empty ( ) & & name . starts_with ( filter ) )
2016-07-15 13:50:02 +03:00
ImportDecl ( parentDecl , childDeclName , childDeclName ,
2016-07-07 11:47:58 +03:00
childDeclContext ) ;
}
}
}
const_cast < DeclContext * > ( childDeclContext ) - >
setHasExternalVisibleStorage ( false ) ;
}
} // end namespace cling