2014-08-06 17:05:09 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Manasij Mukherjee <manasij7479@gmail.com>
// author: Vassil Vassilev <vvasilev@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.
//------------------------------------------------------------------------------
2014-07-12 22:23:55 +04:00
# include "llvm/ADT/SmallVector.h"
# include "llvm/Support/Path.h"
# include "clang/Sema/Sema.h"
# include "clang/Basic/Diagnostic.h"
# include "clang/AST/AST.h"
2014-08-21 14:21:41 +04:00
# include "clang/AST/ASTContext.h" // for operator new[](unsigned long, ASTCtx..)
2014-08-05 23:35:25 +04:00
# include "clang/AST/RecursiveASTVisitor.h"
2014-08-18 23:38:40 +04:00
# include "clang/AST/DeclVisitor.h"
2014-07-12 22:23:55 +04:00
# include "clang/Lex/Preprocessor.h"
2014-07-13 20:43:20 +04:00
# include "clang/Frontend/CompilerInstance.h"
2014-07-12 22:23:55 +04:00
2014-06-08 20:42:58 +04:00
# include "cling/Interpreter/Interpreter.h"
# include "cling/Interpreter/InterpreterCallbacks.h"
2014-06-08 01:52:32 +04:00
# include "cling/Interpreter/AutoloadCallback.h"
2014-07-13 20:43:20 +04:00
# include "cling/Interpreter/Transaction.h"
2014-07-12 22:23:55 +04:00
2014-09-22 17:52:38 +04:00
namespace {
2014-10-02 16:38:33 +04:00
static const char annoTag [ ] = " $clingAutoload$ " ;
static const size_t lenAnnoTag = sizeof ( annoTag ) - 1 ;
2014-09-22 17:52:38 +04:00
}
2014-06-08 01:52:32 +04:00
using namespace clang ;
namespace cling {
2014-07-12 22:23:55 +04:00
2014-09-12 15:53:07 +04:00
void AutoloadCallback : : report ( clang : : SourceLocation l , llvm : : StringRef name ,
llvm : : StringRef header ) {
2014-06-08 01:52:32 +04:00
Sema & sema = m_Interpreter - > getSema ( ) ;
unsigned id
= sema . getDiagnostics ( ) . getCustomDiagID ( DiagnosticsEngine : : Level : : Warning ,
" Note: '%0' can be found in %1 " ) ;
/* unsigned idn //TODO: To be enabled after we have a way to get the full path
= sema . getDiagnostics ( ) . getCustomDiagID ( DiagnosticsEngine : : Level : : Note ,
" Type : %0 , Full Path: %1 " ) */ ;
2014-09-22 17:52:38 +04:00
if ( header . startswith ( llvm : : StringRef ( annoTag , lenAnnoTag ) ) )
sema . Diags . Report ( l , id ) < < name < < header . drop_front ( lenAnnoTag ) ;
2014-06-08 01:52:32 +04:00
}
2014-08-05 04:12:08 +04:00
bool AutoloadCallback : : LookupObject ( TagDecl * t ) {
2014-09-19 15:59:31 +04:00
if ( m_ShowSuggestions & & t - > hasAttr < AnnotateAttr > ( ) )
2014-08-05 04:12:08 +04:00
report ( t - > getLocation ( ) , t - > getNameAsString ( ) , t - > getAttr < AnnotateAttr > ( ) - > getAnnotation ( ) ) ;
return false ;
}
2014-08-18 23:38:40 +04:00
2014-08-20 22:48:23 +04:00
class AutoloadingVisitor : public RecursiveASTVisitor < AutoloadingVisitor > {
2014-08-06 02:07:20 +04:00
private :
bool m_IsStoringState ;
AutoloadCallback : : FwdDeclsMap * m_Map ;
clang : : Preprocessor * m_PP ;
2014-10-02 16:20:51 +04:00
clang : : FileEntry * m_PrevFE ;
std : : string m_PrevFileName ;
2014-08-06 02:07:20 +04:00
private :
2014-09-12 15:57:19 +04:00
void InsertIntoAutoloadingState ( Decl * decl , llvm : : StringRef annotation ) {
assert ( ! annotation . empty ( ) & & " Empty annotation! " ) ;
2014-09-22 17:52:38 +04:00
if ( ! annotation . startswith ( llvm : : StringRef ( annoTag , lenAnnoTag ) ) ) {
2014-09-12 15:57:19 +04:00
// not an autoload annotation.
return ;
}
2014-08-06 02:07:20 +04:00
assert ( m_PP ) ;
const FileEntry * FE = 0 ;
SourceLocation fileNameLoc ;
bool isAngled = false ;
const DirectoryLookup * LookupFrom = 0 ;
const DirectoryLookup * CurDir = 0 ;
2014-10-02 16:20:51 +04:00
if ( m_PrevFE & & m_PrevFileName = = annotation . drop_front ( lenAnnoTag ) )
FE = m_PrevFE ;
else
FE = m_PP - > LookupFile ( fileNameLoc ,
annotation . drop_front ( lenAnnoTag ) , isAngled ,
LookupFrom , CurDir , /*SearchPath*/ 0 ,
/*RelativePath*/ 0 , /*suggestedModule*/ 0 ,
/*SkipCache*/ false , /*OpenFile*/ false ,
/*CacheFail*/ false ) ;
2014-08-06 02:07:20 +04:00
assert ( FE & & " Must have a valid FileEntry " ) ;
2014-10-02 16:20:51 +04:00
auto & Vec = ( * m_Map ) [ FE ] ;
Vec . push_back ( decl ) ;
2014-08-06 02:07:20 +04:00
}
2014-08-05 23:35:25 +04:00
public :
2014-10-02 16:20:51 +04:00
AutoloadingVisitor ( ) :
m_IsStoringState ( false ) , m_Map ( 0 ) , m_PP ( 0 ) , m_PrevFE ( 0 ) { }
2014-08-06 02:07:20 +04:00
void RemoveDefaultArgsOf ( Decl * D ) {
2014-08-06 03:39:34 +04:00
//D = D->getMostRecentDecl();
2014-08-05 23:35:25 +04:00
TraverseDecl ( D ) ;
2014-08-06 03:39:34 +04:00
//while ((D = D->getPreviousDecl()))
// TraverseDecl(D);
2014-07-12 22:23:55 +04:00
}
2014-08-05 23:35:25 +04:00
2014-08-06 02:07:20 +04:00
void TrackDefaultArgStateOf ( Decl * D , AutoloadCallback : : FwdDeclsMap & map ,
Preprocessor & PP ) {
m_IsStoringState = true ;
m_Map = & map ;
m_PP = & PP ;
TraverseDecl ( D ) ;
m_PP = 0 ;
m_Map = 0 ;
m_IsStoringState = false ;
}
2014-08-06 03:39:34 +04:00
bool shouldVisitTemplateInstantiations ( ) { return true ; }
2014-08-05 23:35:25 +04:00
2014-08-06 03:39:34 +04:00
bool VisitDecl ( Decl * D ) {
2014-08-13 16:05:29 +04:00
if ( ! m_IsStoringState )
2014-08-06 14:52:20 +04:00
return true ;
2014-08-08 14:44:32 +04:00
if ( ! D - > hasAttr < AnnotateAttr > ( ) )
2014-08-13 16:05:59 +04:00
return true ;
2014-08-08 14:44:32 +04:00
2014-08-06 14:52:20 +04:00
AnnotateAttr * attr = D - > getAttr < AnnotateAttr > ( ) ;
if ( ! attr )
return true ;
switch ( D - > getKind ( ) ) {
default :
InsertIntoAutoloadingState ( D , attr - > getAnnotation ( ) ) ;
break ;
case Decl : : Enum :
// EnumDecls have extra information 2 chars after the filename used
// for extra fixups.
2014-08-20 22:48:23 +04:00
EnumDecl * ED = cast < EnumDecl > ( D ) ;
if ( ED - > isFixed ( ) ) {
StringRef str = ED - > getAttr < AnnotateAttr > ( ) - > getAnnotation ( ) ;
char ch = str . back ( ) ;
// str.drop_back(2);
ED - > getAttr < AnnotateAttr > ( ) - > setAnnotation ( ED - > getASTContext ( ) , str ) ;
struct EnumDeclDerived : public EnumDecl {
static void setFixed ( EnumDecl * ED , bool value = true ) {
( ( EnumDeclDerived * ) ED ) - > IsFixed = value ;
}
} ;
if ( ch ! = ' 1 ' )
EnumDeclDerived : : setFixed ( ED , false ) ;
}
2014-08-06 14:52:20 +04:00
InsertIntoAutoloadingState ( D , attr - > getAnnotation ( ) . drop_back ( 2 ) ) ;
break ;
2014-08-06 02:07:20 +04:00
}
2014-08-06 03:39:34 +04:00
return true ;
}
2014-08-13 16:06:58 +04:00
bool VisitCXXRecordDecl ( CXXRecordDecl * D ) {
if ( ! D - > hasAttr < AnnotateAttr > ( ) )
return true ;
VisitDecl ( D ) ;
if ( ClassTemplateDecl * TmplD = D - > getDescribedClassTemplate ( ) )
return VisitTemplateDecl ( TmplD ) ;
return true ;
}
bool VisitTemplateTypeParmDecl ( TemplateTypeParmDecl * D ) {
VisitDecl ( D ) ;
if ( m_IsStoringState )
return true ;
if ( D - > hasDefaultArgument ( ) )
D - > removeDefaultArgument ( ) ;
return true ;
}
bool VisitTemplateDecl ( TemplateDecl * D ) {
2014-08-13 19:02:54 +04:00
if ( D - > getTemplatedDecl ( ) & &
! D - > getTemplatedDecl ( ) - > hasAttr < AnnotateAttr > ( ) )
2014-08-12 11:32:38 +04:00
return true ;
2014-08-13 16:06:58 +04:00
VisitDecl ( D ) ;
2014-08-08 14:45:02 +04:00
for ( auto P : D - > getTemplateParameters ( ) - > asArray ( ) )
TraverseDecl ( P ) ;
return true ;
}
2014-08-13 19:02:54 +04:00
bool VisitTemplateTemplateParmDecl ( TemplateTemplateParmDecl * D ) {
VisitDecl ( D ) ;
if ( m_IsStoringState )
return true ;
if ( D - > hasDefaultArgument ( ) )
D - > removeDefaultArgument ( ) ;
return true ;
}
2014-08-13 16:06:58 +04:00
bool VisitNonTypeTemplateParmDecl ( NonTypeTemplateParmDecl * D ) {
VisitDecl ( D ) ;
2014-08-12 11:32:38 +04:00
if ( m_IsStoringState )
return true ;
2014-08-05 23:35:25 +04:00
if ( D - > hasDefaultArgument ( ) )
D - > removeDefaultArgument ( ) ;
return true ;
2014-07-13 21:15:08 +04:00
}
2014-08-05 23:35:25 +04:00
2014-08-13 16:06:58 +04:00
bool VisitParmVarDecl ( ParmVarDecl * D ) {
VisitDecl ( D ) ;
2014-08-12 11:32:38 +04:00
if ( m_IsStoringState )
return true ;
2014-08-05 23:35:25 +04:00
if ( D - > hasDefaultArg ( ) )
D - > setDefaultArg ( nullptr ) ;
return true ;
}
} ;
2014-06-08 01:52:32 +04:00
2014-07-12 22:23:55 +04:00
void AutoloadCallback : : 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 17:58:59 +04:00
// If File is 0 this means that the #included file doesn't exist.
if ( ! File )
return ;
2014-07-30 01:14:15 +04:00
2014-08-06 16:56:28 +04:00
auto found = m_Map . find ( File ) ;
if ( found = = m_Map . end ( ) )
return ; // nothing to do, file not referred in any annotation
2014-07-12 22:23:55 +04:00
2014-08-20 22:48:23 +04:00
AutoloadingVisitor defaultArgsCleaner ;
2014-08-06 16:56:28 +04:00
for ( auto D : found - > second ) {
2014-08-06 02:07:20 +04:00
defaultArgsCleaner . RemoveDefaultArgsOf ( D ) ;
2014-07-12 22:23:55 +04:00
}
2014-08-06 02:07:20 +04:00
// Don't need to keep track of cleaned up decls from file.
2014-08-06 16:56:28 +04:00
m_Map . erase ( found ) ;
2014-07-12 22:23:55 +04:00
}
2014-06-08 01:52:32 +04:00
2014-07-13 20:43:20 +04:00
AutoloadCallback : : ~ AutoloadCallback ( ) {
}
2014-08-06 02:07:20 +04:00
void AutoloadCallback : : TransactionCommitted ( const Transaction & T ) {
2014-08-08 14:45:25 +04:00
if ( T . decls_begin ( ) = = T . decls_end ( ) )
return ;
if ( T . decls_begin ( ) - > m_DGR . isNull ( ) )
return ;
if ( const NamedDecl * ND = dyn_cast < NamedDecl > ( * T . decls_begin ( ) - > m_DGR . begin ( ) ) )
if ( ND - > getIdentifier ( ) & & ND - > getName ( ) . equals ( " __Cling_Autoloading_Map " ) ) {
2014-08-20 22:48:23 +04:00
AutoloadingVisitor defaultArgsStateCollector ;
2014-08-08 14:45:25 +04:00
Preprocessor & PP = m_Interpreter - > getCI ( ) - > getPreprocessor ( ) ;
for ( Transaction : : const_iterator I = T . decls_begin ( ) , E = T . decls_end ( ) ;
I ! = E ; + + I ) {
Transaction : : DelayCallInfo DCI = * I ;
// if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
// continue;
if ( DCI . m_DGR . isNull ( ) )
continue ;
2014-08-18 23:38:40 +04:00
if ( const NamedDecl * ND = dyn_cast < NamedDecl > ( * T . decls_begin ( ) - > m_DGR . begin ( ) ) )
if ( ND - > getIdentifier ( )
& & ND - > getName ( ) . equals ( " __Cling_Autoloading_Map " ) ) {
for ( Transaction : : const_iterator I = T . decls_begin ( ) ,
E = T . decls_end ( ) ; I ! = E ; + + I ) {
Transaction : : DelayCallInfo DCI = * I ;
for ( DeclGroupRef : : iterator J = DCI . m_DGR . begin ( ) ,
JE = DCI . m_DGR . end ( ) ; J ! = JE ; + + J ) {
2014-08-20 22:48:23 +04:00
defaultArgsStateCollector . TrackDefaultArgStateOf ( * J , m_Map , PP ) ;
2014-08-18 23:38:40 +04:00
}
}
}
2014-08-08 14:45:25 +04:00
}
2014-07-13 20:43:20 +04:00
}
}
2014-08-05 23:48:45 +04:00
} //end namespace cling