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"
2015-08-11 16:45:40 +03:00
2014-07-12 22:23:55 +04:00
# 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"
2016-09-10 22:04:39 +03:00
# include "cling/Utils/Output.h"
2016-06-26 11:06:18 +03:00
# include "DeclUnloader.h"
2014-07-12 22:23:55 +04:00
2016-11-18 01:00:06 +03:00
# include <clang/Lex/HeaderSearch.h>
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 " ) */ ;
2024-02-02 13:11:47 +03:00
if ( header . starts_with ( llvm : : StringRef ( annoTag , lenAnnoTag ) ) )
2014-09-22 17:52:38 +04:00
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
2020-02-14 03:26:48 +03:00
class AutoLoadingVisitor : public RecursiveASTVisitor < AutoLoadingVisitor > {
2014-08-06 02:07:20 +04:00
private :
2015-02-05 19:24:50 +03:00
///\brief Flag determining the visitor's actions. If true, register autoload
/// entries, i.e. remember the connection between filename and the declaration
2015-02-05 17:32:42 +03:00
/// that needs to be updated on #include of the filename.
/// If false, react on an #include by adjusting the forward decls, e.g. by
2018-05-16 09:42:15 +03:00
/// removing the default template arguments (that will now be provided by
/// the definition read from the include).
2014-08-06 02:07:20 +04:00
bool m_IsStoringState ;
2016-11-14 02:48:11 +03:00
bool m_IsAutloadEntry ; // True during the traversal of an explicitly annotated decl.
2014-08-06 02:07:20 +04:00
AutoloadCallback : : FwdDeclsMap * m_Map ;
clang : : Preprocessor * m_PP ;
2015-06-19 17:26:08 +03:00
clang : : Sema * m_Sema ;
2016-11-18 01:00:06 +03:00
std : : pair < const clang : : FileEntry * , const clang : : FileEntry * > m_PrevFE ;
std : : pair < std : : string , std : : string > m_PrevFileName ;
2014-08-06 02:07:20 +04:00
private :
2016-11-09 00:52:58 +03:00
bool IsAutoloadEntry ( Decl * D ) {
2016-11-18 01:00:06 +03:00
for ( auto attr = D - > specific_attr_begin < AnnotateAttr > ( ) ,
end = D - > specific_attr_end < AnnotateAttr > ( ) ;
attr ! = end ;
+ + attr )
{
2016-09-10 22:04:39 +03:00
// cling::errs() << "Annotation: " << c->getAnnotation() << "\n";
2016-11-18 01:00:06 +03:00
if ( ! attr - > isInherited ( ) ) {
llvm : : StringRef annotation = attr - > getAnnotation ( ) ;
assert ( ! annotation . empty ( ) & & " Empty annotation! " ) ;
2024-02-02 13:11:47 +03:00
if ( annotation . starts_with ( llvm : : StringRef ( annoTag , lenAnnoTag ) ) ) {
2016-11-09 00:52:58 +03:00
// autoload annotation.
return true ;
2016-11-18 01:00:06 +03:00
}
}
}
return false ;
2016-11-09 00:52:58 +03:00
}
2016-11-18 01:00:06 +03:00
using Annotations_t = std : : pair < llvm : : StringRef , llvm : : StringRef > ;
2014-09-12 15:57:19 +04:00
2020-02-14 03:26:48 +03:00
void InsertIntoAutoLoadingState ( Decl * decl , Annotations_t FileNames ) {
2014-08-06 02:07:20 +04:00
assert ( m_PP ) ;
2016-11-18 01:00:06 +03:00
auto addFile = [ this , decl ] ( llvm : : StringRef FileName , bool warn ) {
if ( FileName . empty ( ) ) return ( const FileEntry * ) nullptr ;
const FileEntry * FE = 0 ;
SourceLocation fileNameLoc ;
2017-12-06 02:10:44 +03:00
// Remember this file wth full path, not "./File.h" (ROOT-8863).
bool isAngled = true ;
2023-01-18 10:42:47 +03:00
ConstSearchDirIterator FromDir = nullptr ;
2016-11-18 01:00:06 +03:00
const FileEntry * FromFile = 0 ;
2023-01-18 10:42:47 +03:00
ConstSearchDirIterator * CurDir = nullptr ;
2016-11-18 01:00:06 +03:00
bool needCacheUpdate = false ;
if ( FileName . equals ( m_PrevFileName . first ) )
FE = m_PrevFE . first ;
else if ( FileName . equals ( m_PrevFileName . second ) )
FE = m_PrevFE . second ;
2022-12-18 00:58:57 +03:00
else if ( auto FERef = m_PP - > LookupFile ( fileNameLoc , FileName , isAngled ,
FromDir , FromFile , CurDir ,
/*SearchPath*/ 0 , /*RelativePath*/ 0 ,
/*suggestedModule*/ 0 , /*IsMapped*/ 0 ,
/*IsFrameworkFound*/ nullptr ,
/*SkipCache*/ false ,
/*OpenFile*/ false ,
/*CacheFail*/ true ) ) {
2016-11-18 01:00:06 +03:00
needCacheUpdate = true ;
2022-12-18 00:58:57 +03:00
FE = & FERef - > getFileEntry ( ) ;
2016-11-18 01:00:06 +03:00
}
2014-08-06 02:07:20 +04:00
2016-11-18 01:00:06 +03:00
if ( FE ) {
auto & Vec = ( * m_Map ) [ FE ] ;
Vec . push_back ( decl ) ;
2022-12-18 00:58:57 +03:00
if ( needCacheUpdate )
return FE ;
else
return ( const FileEntry * ) nullptr ;
2016-11-18 01:00:06 +03:00
} else if ( warn ) {
// If the top level header is expected to be findable at run-time,
// the direct header might not because the include path might be
// different enough and only the top-header is guaranteed to be seen
// by the user as an interface header to be available on the
// run-time include path.
2016-09-10 22:04:39 +03:00
cling : : errs ( )
2020-02-14 03:26:48 +03:00
< < " Error in cling::AutoLoadingVisitor::InsertIntoAutoLoadingState: \n "
2015-08-11 16:45:40 +03:00
" Missing FileEntry for " < < FileName < < " \n " ;
2016-11-18 01:00:06 +03:00
if ( NamedDecl * ND = dyn_cast < NamedDecl > ( decl ) ) {
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " requested to autoload type " ;
ND - > getNameForDiagnostic ( cling : : errs ( ) ,
2016-11-18 01:00:06 +03:00
ND - > getASTContext ( ) . getPrintingPolicy ( ) ,
true /*qualified*/ ) ;
2016-09-10 22:04:39 +03:00
cling : : errs ( ) < < " \n " ;
2016-11-18 01:00:06 +03:00
}
return ( const FileEntry * ) nullptr ;
2015-08-11 16:45:40 +03:00
}
2022-12-18 00:58:57 +03:00
// Case of the direct header that is not a top level header, no
// warning in this case (to likely to be a false positive).
return ( const FileEntry * ) nullptr ;
2016-11-18 01:00:06 +03:00
} ;
const FileEntry * cacheUpdate ;
if ( ( cacheUpdate = addFile ( FileNames . first , true ) ) ) {
m_PrevFE . first = cacheUpdate ;
2021-09-11 21:12:30 +03:00
m_PrevFileName . first = FileNames . first . str ( ) ;
2016-11-18 01:00:06 +03:00
}
if ( ( cacheUpdate = addFile ( FileNames . second , false ) ) ) {
m_PrevFE . second = cacheUpdate ;
2021-09-11 21:12:30 +03:00
m_PrevFileName . second = FileNames . second . str ( ) ;
2014-10-02 18:26:08 +04:00
}
2016-11-18 01:00:06 +03:00
2014-08-06 02:07:20 +04:00
}
2014-08-05 23:35:25 +04:00
public :
2020-02-14 03:26:48 +03:00
AutoLoadingVisitor ( ) :
2016-11-14 02:48:11 +03:00
m_IsStoringState ( false ) , m_IsAutloadEntry ( false ) , m_Map ( 0 ) , m_PP ( 0 ) ,
2016-11-18 01:00:06 +03:00
m_Sema ( 0 ) , m_PrevFE ( { nullptr , nullptr } )
2016-11-14 02:48:11 +03:00
{ }
2015-06-19 17:26:08 +03:00
void RemoveDefaultArgsOf ( Decl * D , Sema * S ) {
m_Sema = S ;
2016-11-08 20:21:43 +03:00
2016-11-14 02:45:31 +03:00
auto cursor = D - > getMostRecentDecl ( ) ;
2016-11-14 02:48:11 +03:00
m_IsAutloadEntry = IsAutoloadEntry ( cursor ) ;
2016-11-14 02:45:31 +03:00
TraverseDecl ( cursor ) ;
while ( cursor ! = D & & ( cursor = cursor - > getPreviousDecl ( ) ) ) {
2016-11-14 02:48:11 +03:00
m_IsAutloadEntry = IsAutoloadEntry ( cursor ) ;
2016-11-14 02:45:31 +03:00
TraverseDecl ( cursor ) ;
2016-11-08 20:21:43 +03:00
}
2016-11-14 02:48:11 +03:00
m_IsAutloadEntry = false ;
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
2016-11-18 01:00:06 +03:00
Annotations_t annotations ;
for ( auto attr = D - > specific_attr_begin < AnnotateAttr > ( ) ,
end = D - > specific_attr_end < AnnotateAttr > ( ) ;
attr ! = end ;
+ + attr )
{
if ( ! attr - > isInherited ( ) ) {
auto annot = attr - > getAnnotation ( ) ;
2024-02-02 13:11:47 +03:00
if ( annot . starts_with ( llvm : : StringRef ( annoTag , lenAnnoTag ) ) ) {
2016-11-18 01:00:06 +03:00
if ( annotations . first . empty ( ) ) {
annotations . first = annot . drop_front ( lenAnnoTag ) ;
} else {
annotations . second = annot . drop_front ( lenAnnoTag ) ;
}
}
}
}
2020-02-14 03:26:48 +03:00
InsertIntoAutoLoadingState ( D , annotations ) ;
2014-08-06 03:39:34 +04:00
return true ;
}
2014-08-13 16:06:58 +04:00
bool VisitCXXRecordDecl ( CXXRecordDecl * D ) {
2016-11-14 02:49:24 +03:00
// Since we are only interested in fixing forward declaration
// there is no need to continue on when we see a complete definition.
if ( D - > isCompleteDefinition ( ) )
return false ;
2014-08-13 16:06:58 +04:00
if ( ! D - > hasAttr < AnnotateAttr > ( ) )
return true ;
if ( ClassTemplateDecl * TmplD = D - > getDescribedClassTemplate ( ) )
return VisitTemplateDecl ( TmplD ) ;
return true ;
}
bool VisitTemplateTypeParmDecl ( TemplateTypeParmDecl * D ) {
if ( m_IsStoringState )
return true ;
2016-11-14 02:48:11 +03:00
if ( m_IsAutloadEntry ) {
if ( D - > hasDefaultArgument ( ) & & ! D - > defaultArgumentWasInherited ( ) )
D - > removeDefaultArgument ( ) ;
} else {
if ( D - > hasDefaultArgument ( ) & & D - > defaultArgumentWasInherited ( ) )
D - > removeDefaultArgument ( ) ;
}
2014-08-13 16:06:58 +04:00
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
2015-02-05 17:33:28 +03:00
// If we have a definition we might be about to re-#include the
// same header containing definition that was #included previously,
// i.e. we might have multiple fwd decls for the same template.
// DO NOT remove the defaults here; the definition needs to keep it.
// (ROOT-7037)
if ( ClassTemplateDecl * CTD = dyn_cast < ClassTemplateDecl > ( D ) )
if ( CXXRecordDecl * TemplatedD = CTD - > getTemplatedDecl ( ) )
if ( TemplatedD - > getDefinition ( ) )
return true ;
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 ) {
if ( m_IsStoringState )
return true ;
2016-11-14 02:48:11 +03:00
if ( m_IsAutloadEntry ) {
if ( D - > hasDefaultArgument ( ) & & ! D - > defaultArgumentWasInherited ( ) )
D - > removeDefaultArgument ( ) ;
} else {
if ( D - > hasDefaultArgument ( ) & & D - > defaultArgumentWasInherited ( ) )
D - > removeDefaultArgument ( ) ;
}
2014-08-13 19:02:54 +04:00
return true ;
}
2014-08-13 16:06:58 +04:00
bool VisitNonTypeTemplateParmDecl ( NonTypeTemplateParmDecl * D ) {
2014-08-12 11:32:38 +04:00
if ( m_IsStoringState )
return true ;
2016-11-14 02:48:11 +03:00
if ( m_IsAutloadEntry ) {
if ( D - > hasDefaultArgument ( ) & & ! D - > defaultArgumentWasInherited ( ) )
D - > removeDefaultArgument ( ) ;
} else {
if ( D - > hasDefaultArgument ( ) & & D - > defaultArgumentWasInherited ( ) )
D - > removeDefaultArgument ( ) ;
}
2014-08-05 23:35:25 +04:00
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 ) {
2014-08-12 11:32:38 +04:00
if ( m_IsStoringState )
return true ;
2016-11-14 02:48:11 +03:00
if ( m_IsAutloadEntry ) {
if ( D - > hasDefaultArg ( ) & & ! D - > hasInheritedDefaultArg ( ) )
D - > setDefaultArg ( nullptr ) ;
} else {
if ( D - > hasDefaultArg ( ) & & D - > hasInheritedDefaultArg ( ) )
D - > setDefaultArg ( nullptr ) ;
}
2014-08-05 23:35:25 +04:00
return true ;
}
} ;
2014-06-08 01:52:32 +04:00
2020-09-30 18:46:22 +03:00
void AutoloadCallback : : InclusionDirective ( clang : : SourceLocation /*HashLoc*/ ,
const clang : : Token & /*IncludeTok*/ ,
llvm : : StringRef /*FileName*/ ,
bool /*IsAngled*/ ,
clang : : CharSourceRange /*FilenameRange*/ ,
2023-07-10 09:37:18 +03:00
clang : : OptionalFileEntryRef File ,
2020-09-30 18:46:22 +03:00
llvm : : StringRef /*SearchPath*/ ,
llvm : : StringRef /*RelativePath*/ ,
const clang : : Module */ * Imported */ ,
clang : : SrcMgr : : CharacteristicKind /*FileType*/ ) {
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
2023-07-10 09:37:18 +03:00
auto found = m_Map . find ( * File ) ;
2014-08-06 16:56:28 +04:00
if ( found = = m_Map . end ( ) )
return ; // nothing to do, file not referred in any annotation
2014-07-12 22:23:55 +04:00
2020-02-14 03:26:48 +03:00
AutoLoadingVisitor defaultArgsCleaner ;
2014-08-06 16:56:28 +04:00
for ( auto D : found - > second ) {
2015-06-19 17:26:08 +03:00
defaultArgsCleaner . RemoveDefaultArgsOf ( D , & getInterpreter ( ) - > getSema ( ) ) ;
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 ;
2015-06-22 16:18:05 +03:00
// The first decl must be
2020-02-14 03:26:48 +03:00
// extern int __Cling_AutoLoading_Map;
bool HaveAutoLoadingMapMarker = false ;
2015-06-22 16:18:05 +03:00
for ( auto I = T . decls_begin ( ) , E = T . decls_end ( ) ;
2020-02-14 03:26:48 +03:00
! HaveAutoLoadingMapMarker & & I ! = E ; + + I ) {
2015-06-22 16:18:05 +03:00
if ( I - > m_Call ! = cling : : Transaction : : kCCIHandleTopLevelDecl )
return ;
for ( auto & & D : I - > m_DGR ) {
if ( isa < EmptyDecl > ( D ) )
continue ;
else if ( auto VD = dyn_cast < VarDecl > ( D ) ) {
2020-02-14 03:26:48 +03:00
HaveAutoLoadingMapMarker
2015-06-22 16:18:05 +03:00
= VD - > hasExternalStorage ( ) & & VD - > getIdentifier ( )
2020-02-14 03:26:48 +03:00
& & VD - > getName ( ) . equals ( " __Cling_AutoLoading_Map " ) ;
if ( ! HaveAutoLoadingMapMarker )
2015-06-22 16:18:05 +03:00
return ;
break ;
} else
return ;
2014-07-13 20:43:20 +04:00
}
2015-06-22 16:18:05 +03:00
}
2020-02-14 03:26:48 +03:00
if ( ! HaveAutoLoadingMapMarker )
2015-06-22 16:18:05 +03:00
return ;
2020-02-14 03:26:48 +03:00
AutoLoadingVisitor defaultArgsStateCollector ;
2015-06-22 16:18:05 +03:00
Preprocessor & PP = m_Interpreter - > getCI ( ) - > getPreprocessor ( ) ;
for ( auto I = T . decls_begin ( ) , E = T . decls_end ( ) ; I ! = E ; + + I )
for ( auto & & D : I - > m_DGR )
defaultArgsStateCollector . TrackDefaultArgStateOf ( D , m_Map , PP ) ;
2014-07-13 20:43:20 +04:00
}
2014-08-05 23:48:45 +04:00
} //end namespace cling