2012-10-09 10:17:19 +00:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vvasilev@cern.ch>
2014-01-07 11:08:37 +01:00
//
// 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.
2012-10-09 10:17:19 +00:00
//------------------------------------------------------------------------------
# include "cling/Interpreter/InterpreterCallbacks.h"
# include "cling/Interpreter/Interpreter.h"
2013-10-03 11:43:52 +02:00
# include "clang/AST/ASTContext.h"
2013-08-22 10:28:43 +02:00
# include "clang/Frontend/CompilerInstance.h"
2013-08-22 13:45:06 +02:00
# include "clang/Lex/Preprocessor.h"
2012-10-09 10:17:19 +00:00
# include "clang/Sema/Sema.h"
2013-08-22 10:28:43 +02:00
# include "clang/Serialization/ASTReader.h"
# include "clang/Serialization/ASTDeserializationListener.h"
2012-10-10 13:00:17 +00:00
using namespace clang ;
2012-10-09 10:17:19 +00:00
namespace cling {
2014-08-03 21:05:42 -05:00
///\brief Translates 'interesting' for the interpreter
2013-08-22 13:45:06 +02:00
/// ASTDeserializationListener events into interpreter callback.
///
class InterpreterPPCallbacks : public PPCallbacks {
private :
cling : : InterpreterCallbacks * m_Callbacks ;
public :
InterpreterPPCallbacks ( InterpreterCallbacks * C ) : m_Callbacks ( C ) { }
~ InterpreterPPCallbacks ( ) { }
2014-01-28 14:52:22 +01:00
virtual void InclusionDirective ( clang : : SourceLocation HashLoc ,
const clang : : Token & IncludeTok ,
llvm : : StringRef FileName ,
bool IsAngled ,
clang : : CharSourceRange FilenameRange ,
const clang : : FileEntry * File ,
llvm : : StringRef SearchPath ,
llvm : : StringRef RelativePath ,
const clang : : Module * Imported ) {
2014-08-21 15:57:54 +02:00
m_Callbacks - > InclusionDirective ( HashLoc , IncludeTok , FileName ,
2014-08-08 17:09:34 +02:00
IsAngled , FilenameRange , File ,
2014-08-21 15:57:54 +02:00
SearchPath , RelativePath , Imported ) ;
2014-01-28 14:52:22 +01:00
}
2014-08-08 17:09:34 +02:00
2013-08-22 13:45:06 +02:00
virtual bool FileNotFound ( llvm : : StringRef FileName ,
llvm : : SmallVectorImpl < char > & RecoveryPath ) {
2014-08-21 15:57:54 +02:00
if ( m_Callbacks )
return m_Callbacks - > FileNotFound ( FileName , RecoveryPath ) ;
2013-08-22 13:45:06 +02:00
// Returning true would mean that the preprocessor should try to recover.
return false ;
}
} ;
2014-08-03 21:05:42 -05:00
///\brief Translates 'interesting' for the interpreter
2013-08-22 10:28:43 +02:00
/// ASTDeserializationListener events into interpreter callback.
///
class InterpreterDeserializationListener : public ASTDeserializationListener {
private :
cling : : InterpreterCallbacks * m_Callbacks ;
public :
InterpreterDeserializationListener ( InterpreterCallbacks * C )
: m_Callbacks ( C ) { }
virtual void DeclRead ( serialization : : DeclID , const Decl * D ) {
2014-08-21 15:57:54 +02:00
if ( m_Callbacks )
2013-08-22 10:28:43 +02:00
m_Callbacks - > DeclDeserialized ( D ) ;
}
2014-08-08 17:09:34 +02:00
2013-08-22 10:28:43 +02:00
virtual void TypeRead ( serialization : : TypeIdx , QualType T ) {
2014-08-21 15:57:54 +02:00
if ( m_Callbacks )
2013-08-22 10:28:43 +02:00
m_Callbacks - > TypeDeserialized ( T . getTypePtr ( ) ) ;
}
} ;
2014-08-03 21:05:42 -05:00
///\brief Translates 'interesting' for the interpreter ExternalSemaSource
2013-08-21 16:45:14 +02:00
/// events into interpreter callbacks.
///
class InterpreterExternalSemaSource : public clang : : ExternalSemaSource {
protected :
///\brief The interpreter callback which are subscribed for the events.
///
/// Usually the callbacks is the owner of the class and the interpreter owns
/// the callbacks so they can't be out of sync. Eg we notifying the wrong
/// callback class.
///
InterpreterCallbacks * m_Callbacks ; // we don't own it.
2013-10-03 11:43:52 +02:00
Sema * m_Sema ; // we don't own // FIXME: once we remove ForgetSema delete.
2013-08-21 16:45:14 +02:00
public :
2014-08-03 21:05:42 -05:00
InterpreterExternalSemaSource ( InterpreterCallbacks * C )
2013-10-03 11:43:52 +02:00
: m_Callbacks ( C ) , m_Sema ( 0 ) { }
~ InterpreterExternalSemaSource ( ) {
// FIXME: Another gross hack due to the missing multiplexing AST external
// source see Interpreter::setCallbacks.
if ( m_Sema ) {
ASTContext & C = m_Sema - > getASTContext ( ) ;
// tell the owning ptr to not delete it, the callbacks will delete it.
2014-08-01 14:04:43 +02:00
if ( C . ExternalSource . get ( ) = = this )
2014-03-03 17:57:47 +01:00
C . ExternalSource . resetWithoutRelease ( ) ;
2013-10-03 11:43:52 +02:00
}
}
2013-08-21 16:45:14 +02:00
2013-10-03 11:43:52 +02:00
virtual void InitializeSema ( Sema & S ) {
m_Sema = & S ;
}
virtual void ForgetSema ( ) {
m_Sema = 0 ;
}
2013-08-21 16:45:14 +02:00
InterpreterCallbacks * getCallbacks ( ) const { return m_Callbacks ; }
/// \brief Provides last resort lookup for failed unqualified lookups.
///
/// This gets translated into InterpreterCallback's call.
///
///\param[out] R The recovered symbol.
///\param[in] S The scope in which the lookup failed.
///
///\returns true if a suitable declaration is found.
///
virtual bool LookupUnqualified ( clang : : LookupResult & R , clang : : Scope * S ) {
2014-08-08 17:09:34 +02:00
if ( m_Callbacks ) {
2014-08-21 15:57:54 +02:00
return m_Callbacks - > LookupObject ( R , S ) ;
2014-08-08 17:09:34 +02:00
}
2014-08-03 21:05:42 -05:00
2013-08-21 16:45:14 +02:00
return false ;
}
virtual bool FindExternalVisibleDeclsByName ( const clang : : DeclContext * DC ,
clang : : DeclarationName Name ) {
2014-08-21 15:57:54 +02:00
if ( m_Callbacks )
return m_Callbacks - > LookupObject ( DC , Name ) ;
2013-08-21 16:45:14 +02:00
return false ;
}
2014-08-08 17:09:34 +02:00
2013-09-09 13:59:21 +02:00
// Silence warning virtual function was hidden.
2013-09-09 14:28:19 +02:00
using ExternalASTSource : : CompleteType ;
2013-09-09 11:35:05 +02:00
virtual void CompleteType ( TagDecl * Tag ) {
2014-08-21 15:57:54 +02:00
if ( m_Callbacks )
2013-09-09 11:35:05 +02:00
m_Callbacks - > LookupObject ( Tag ) ;
}
2014-08-03 21:05:42 -05:00
void UpdateWithNewDeclsFwd ( const DeclContext * DC , DeclarationName Name ,
2013-08-21 16:45:14 +02:00
llvm : : ArrayRef < NamedDecl * > Decls ) {
SetExternalVisibleDeclsForName ( DC , Name , Decls ) ;
}
} ;
2012-10-09 10:17:19 +00:00
2013-08-22 10:28:43 +02:00
InterpreterCallbacks : : InterpreterCallbacks ( Interpreter * interp ,
bool enableExternalSemaSourceCallbacks /* = false*/ ,
2013-08-22 13:45:06 +02:00
bool enableDeserializationListenerCallbacks /* = false*/ ,
bool enablePPCallbacks /* = false*/ )
2014-08-21 16:05:32 +02:00
: m_Interpreter ( interp ) , m_IsRuntime ( false ) {
Sema & SemaRef = interp - > getSema ( ) ;
2014-08-23 19:04:17 +02:00
ASTReader * Reader = m_Interpreter - > getCI ( ) - > getModuleManager ( ) . get ( ) ;
ExternalSemaSource * externalSemaSrc = SemaRef . getExternalSource ( ) ;
if ( enableExternalSemaSourceCallbacks )
if ( ! externalSemaSrc | | externalSemaSrc = = Reader ) {
// If the ExternalSemaSource is the PCH reader we still need to insert
// our listener.
2014-10-01 12:30:38 +02:00
m_ExternalSemaSource = new InterpreterExternalSemaSource ( this ) ;
2014-08-23 19:04:17 +02:00
m_ExternalSemaSource - > InitializeSema ( SemaRef ) ;
2014-10-01 12:30:38 +02:00
m_Interpreter - > getSema ( ) . addExternalSource ( m_ExternalSemaSource ) ;
2014-08-23 19:04:17 +02:00
// FIXME: We should add a multiplexer in the ASTContext, too.
llvm : : IntrusiveRefCntPtr < ExternalASTSource >
astContextExternalSource ( SemaRef . getExternalSource ( ) ) ;
clang : : ASTContext & Ctx = SemaRef . getASTContext ( ) ;
// FIXME: This is a gross hack. We must make multiplexer in the
// astcontext or a derived class that extends what we need.
Ctx . ExternalSource . resetWithoutRelease ( ) ; //FIXME: make sure we delete it.
Ctx . setExternalSource ( astContextExternalSource ) ;
2013-08-22 10:28:43 +02:00
}
if ( enableDeserializationListenerCallbacks & & Reader ) {
// FIXME: need to create a multiplexer if a DeserializationListener is
// alreday present.
m_DeserializationListener .
reset ( new InterpreterDeserializationListener ( this ) ) ;
Reader - > setDeserializationListener ( m_DeserializationListener . get ( ) ) ;
}
2013-08-22 13:45:06 +02:00
if ( enablePPCallbacks ) {
Preprocessor & PP = m_Interpreter - > getCI ( ) - > getPreprocessor ( ) ;
2015-01-15 15:13:14 +01:00
m_PPCallbacks = new InterpreterPPCallbacks ( this ) ;
PP . addPPCallbacks ( std : : unique_ptr < InterpreterPPCallbacks > ( m_PPCallbacks ) ) ;
2013-08-22 13:45:06 +02:00
}
2012-10-09 10:17:19 +00:00
}
// pin the vtable here
2012-10-14 14:20:08 +00:00
InterpreterCallbacks : : ~ InterpreterCallbacks ( ) {
// FIXME: we have to remove the external source at destruction time. Needs
2014-08-03 21:05:42 -05:00
// further tweaks of the patch in clang. This will be done later once the
2012-10-14 14:20:08 +00:00
// patch is in clang's mainline.
}
2012-10-09 10:17:19 +00:00
2014-08-08 17:09:34 +02:00
void InterpreterCallbacks : : SetIsRuntime ( bool val ) {
m_IsRuntime = val ;
}
2014-08-03 21:05:42 -05:00
ExternalSemaSource *
2013-08-22 10:28:43 +02:00
InterpreterCallbacks : : getInterpreterExternalSemaSource ( ) const {
2014-10-01 12:30:38 +02:00
return m_ExternalSemaSource ;
2013-08-22 10:28:43 +02:00
}
2014-08-03 21:05:42 -05:00
ASTDeserializationListener *
2013-08-22 10:28:43 +02:00
InterpreterCallbacks : : getInterpreterDeserializationListener ( ) const {
return m_DeserializationListener . get ( ) ;
}
2014-08-03 21:05:42 -05:00
bool InterpreterCallbacks : : FileNotFound ( llvm : : StringRef FileName ,
2013-08-22 13:45:06 +02:00
llvm : : SmallVectorImpl < char > & RecoveryPath ) {
// Default implementation is no op.
return false ;
}
2012-10-10 13:00:17 +00:00
bool InterpreterCallbacks : : LookupObject ( LookupResult & , Scope * ) {
2013-08-22 13:45:06 +02:00
// Default implementation is no op.
2012-10-09 10:17:19 +00:00
return false ;
}
2013-08-20 11:35:25 +02:00
bool InterpreterCallbacks : : LookupObject ( const DeclContext * , DeclarationName ) {
2013-08-22 13:45:06 +02:00
// Default implementation is no op.
2013-08-20 11:35:25 +02:00
return false ;
}
2013-09-09 11:35:05 +02:00
bool InterpreterCallbacks : : LookupObject ( TagDecl * ) {
// Default implementation is no op.
return false ;
}
2014-08-03 21:05:42 -05:00
void InterpreterCallbacks : : UpdateWithNewDecls ( const DeclContext * DC ,
DeclarationName Name ,
2013-08-21 16:45:14 +02:00
llvm : : ArrayRef < NamedDecl * > Decls ) {
2013-08-22 10:28:43 +02:00
if ( m_ExternalSemaSource )
m_ExternalSemaSource - > UpdateWithNewDeclsFwd ( DC , Name , Decls ) ;
}
2012-10-09 10:17:19 +00:00
} // end namespace cling
2012-10-10 13:00:17 +00:00
// TODO: Make the build system in the testsuite aware how to build that class
// and extract it out there again.
2012-10-10 15:50:17 +00:00
# include "DynamicLookup.h"
2012-10-10 13:00:17 +00:00
# include "cling/Utils/AST.h"
2012-10-10 15:50:17 +00:00
2013-02-14 17:29:30 +00:00
# include "clang/AST/ASTContext.h"
2012-10-10 15:50:17 +00:00
# include "clang/Lex/Preprocessor.h"
2013-02-14 17:29:30 +00:00
# include "clang/Sema/Lookup.h"
2012-10-10 15:50:17 +00:00
# include "clang/Sema/Scope.h"
2012-10-10 13:00:17 +00:00
namespace cling {
namespace test {
TestProxy * Tester = 0 ;
extern " C " int printf ( const char * fmt , . . . ) ;
TestProxy : : TestProxy ( ) { }
int TestProxy : : Draw ( ) { return 12 ; }
const char * TestProxy : : getVersion ( ) { return " Interpreter.cpp " ; }
int TestProxy : : Add10 ( int num ) { return num + 10 ; }
int TestProxy : : Add ( int a , int b ) {
return a + b ;
}
void TestProxy : : PrintString ( std : : string s ) { printf ( " %s \n " , s . c_str ( ) ) ; }
bool TestProxy : : PrintArray ( int a [ ] , size_t size ) {
for ( unsigned i = 0 ; i < size ; + + i )
printf ( " %i " , a [ i ] ) ;
printf ( " %s " , " \n " ) ;
return true ;
}
void TestProxy : : PrintArray ( float a [ ] [ 5 ] , size_t size ) {
for ( unsigned i = 0 ; i < size ; + + i )
for ( unsigned j = 0 ; j < 5 ; + + j )
printf ( " %i " , ( int ) a [ i ] [ j ] ) ;
printf ( " %s " , " \n " ) ;
}
void TestProxy : : PrintArray ( int a [ ] [ 4 ] [ 5 ] , size_t size ) {
for ( unsigned i = 0 ; i < size ; + + i )
for ( unsigned j = 0 ; j < 4 ; + + j )
for ( unsigned k = 0 ; k < 5 ; + + k )
printf ( " %i " , a [ i ] [ j ] [ k ] ) ;
printf ( " %s " , " \n " ) ;
}
2012-10-10 15:50:17 +00:00
SymbolResolverCallback : : SymbolResolverCallback ( Interpreter * interp )
2014-08-22 09:13:16 +02:00
: InterpreterCallbacks ( interp ) , m_TesterDecl ( 0 ) {
2012-10-10 13:00:17 +00:00
m_Interpreter - > process ( " cling::test::Tester = new cling::test::TestProxy(); " ) ;
}
2012-10-10 14:37:10 +00:00
SymbolResolverCallback : : ~ SymbolResolverCallback ( ) { }
2012-10-10 13:00:17 +00:00
bool SymbolResolverCallback : : LookupObject ( LookupResult & R , Scope * S ) {
2013-02-14 17:29:30 +00:00
if ( m_IsRuntime ) {
// Only for demo resolve all unknown objects to cling::test::Tester
if ( ! m_TesterDecl ) {
clang : : Sema & SemaR = m_Interpreter - > getSema ( ) ;
clang : : NamespaceDecl * NSD = utils : : Lookup : : Namespace ( & SemaR , " cling " ) ;
NSD = utils : : Lookup : : Namespace ( & SemaR , " test " , NSD ) ;
m_TesterDecl = utils : : Lookup : : Named ( & SemaR , " Tester " , NSD ) ;
}
assert ( m_TesterDecl & & " Tester not found! " ) ;
R . addDecl ( m_TesterDecl ) ;
return true ; // Tell clang to continue.
}
if ( ShouldResolveAtRuntime ( R , S ) ) {
ASTContext & C = R . getSema ( ) . getASTContext ( ) ;
DeclContext * DC = 0 ;
// For DeclContext-less scopes like if (dyn_expr) {}
while ( ! DC ) {
DC = static_cast < DeclContext * > ( S - > getEntity ( ) ) ;
S = S - > getParent ( ) ;
}
DeclarationName Name = R . getLookupName ( ) ;
IdentifierInfo * II = Name . getAsIdentifierInfo ( ) ;
SourceLocation Loc = R . getNameLoc ( ) ;
VarDecl * Res = VarDecl : : Create ( C , DC , Loc , Loc , II , C . DependentTy ,
2013-04-24 16:28:08 +00:00
/*TypeSourceInfo*/ 0 , SC_None ) ;
2013-02-14 17:29:30 +00:00
// Annotate the decl to give a hint in cling. FIXME: Current implementation
2014-08-03 21:05:42 -05:00
// is a gross hack, because TClingCallbacks shouldn't know about
2013-02-14 17:29:30 +00:00
// EvaluateTSynthesizer at all!
SourceRange invalidRange ;
2014-02-18 08:22:16 +01:00
Res - > addAttr ( new ( C ) AnnotateAttr ( invalidRange , C , " __ResolveAtRuntime " , 0 ) ) ;
2013-02-14 17:29:30 +00:00
R . addDecl ( Res ) ;
DC - > addDecl ( Res ) ;
// Say that we can handle the situation. Clang should try to recover
return true ;
}
return false ;
}
2014-08-03 21:05:42 -05:00
bool SymbolResolverCallback : : ShouldResolveAtRuntime ( LookupResult & R ,
2013-02-14 17:29:30 +00:00
Scope * S ) {
2014-08-03 21:05:42 -05:00
if ( R . getLookupKind ( ) ! = Sema : : LookupOrdinaryName )
2012-10-10 14:37:10 +00:00
return false ;
2013-02-14 17:29:30 +00:00
2014-08-03 21:05:42 -05:00
if ( R . isForRedeclaration ( ) )
2013-02-14 17:29:30 +00:00
return false ;
2012-11-15 16:41:10 +00:00
if ( ! R . empty ( ) )
return false ;
2012-10-10 14:37:10 +00:00
2013-02-14 17:29:30 +00:00
// FIXME: Figure out better way to handle:
// C++ [basic.lookup.classref]p1:
// In a class member access expression (5.2.5), if the . or -> token is
// immediately followed by an identifier followed by a <, the
// identifier must be looked up to determine whether the < is the
// beginning of a template argument list (14.2) or a less-than operator.
// The identifier is first looked up in the class of the object
// expression. If the identifier is not found, it is then looked up in
// the context of the entire postfix-expression and shall name a class
// or function template.
//
// We want to ignore object(.|->)member<template>
if ( R . getSema ( ) . PP . LookAhead ( 0 ) . getKind ( ) = = tok : : less )
// TODO: check for . or -> in the cached token stream
return false ;
for ( Scope * DepScope = S ; DepScope ; DepScope = DepScope - > getParent ( ) ) {
if ( DeclContext * Ctx = static_cast < DeclContext * > ( DepScope - > getEntity ( ) ) ) {
if ( ! Ctx - > isDependentContext ( ) )
// For now we support only the prompt.
if ( isa < FunctionDecl > ( Ctx ) )
return true ;
}
2012-10-10 13:00:17 +00:00
}
2013-02-14 17:29:30 +00:00
return false ;
2012-10-10 13:00:17 +00:00
}
2013-02-14 17:29:30 +00:00
2012-10-10 13:00:17 +00:00
} // end test
} // end cling