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-05 23:35:25 +04:00
# include "clang/AST/RecursiveASTVisitor.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-06-08 01:52:32 +04:00
using namespace clang ;
namespace cling {
2014-07-12 22:23:55 +04:00
2014-06-08 01:52:32 +04:00
void AutoloadCallback : : report ( clang : : SourceLocation l , std : : string name , std : : string header ) {
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 " ) */ ;
sema . Diags . Report ( l , id ) < < name < < header ;
}
2014-08-05 04:12:08 +04:00
bool AutoloadCallback : : LookupObject ( TagDecl * t ) {
if ( t - > hasAttr < AnnotateAttr > ( ) )
report ( t - > getLocation ( ) , t - > getNameAsString ( ) , t - > getAttr < AnnotateAttr > ( ) - > getAnnotation ( ) ) ;
return false ;
}
2014-07-12 22:23:55 +04:00
2014-08-06 02:07:20 +04:00
class DefaultArgVisitor : public RecursiveASTVisitor < DefaultArgVisitor > {
private :
bool m_IsStoringState ;
AutoloadCallback : : FwdDeclsMap * m_Map ;
clang : : Preprocessor * m_PP ;
private :
void InsertIntoAutoloadingState ( Decl * decl , std : : string annotation ) {
assert ( annotation ! = " " & & " Empty annotation! " ) ;
assert ( m_PP ) ;
const FileEntry * FE = 0 ;
SourceLocation fileNameLoc ;
bool isAngled = false ;
const DirectoryLookup * LookupFrom = 0 ;
const DirectoryLookup * CurDir = 0 ;
FE = m_PP - > LookupFile ( fileNameLoc , annotation , isAngled , LookupFrom ,
CurDir , /*SearchPath*/ 0 , /*RelativePath*/ 0 ,
/*suggestedModule*/ 0 , /*SkipCache*/ false ,
/*OpenFile*/ false , /*CacheFail*/ false ) ;
assert ( FE & & " Must have a valid FileEntry " ) ;
2014-08-06 03:39:34 +04:00
if ( m_Map - > find ( FE ) = = m_Map - > end ( ) )
2014-08-06 02:07:20 +04:00
( * m_Map ) [ FE ] = std : : vector < Decl * > ( ) ;
( * m_Map ) [ FE ] . push_back ( decl ) ;
}
2014-08-05 23:35:25 +04:00
public :
2014-08-06 02:07:20 +04:00
DefaultArgVisitor ( ) : m_IsStoringState ( false ) , m_Map ( 0 ) { }
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-06 14:52:20 +04:00
bool TraverseTemplateTypeParmDecl ( TemplateTypeParmDecl * D ) {
2014-08-06 03:39:34 +04:00
if ( D - > hasDefaultArgument ( ) )
2014-08-05 23:35:25 +04:00
D - > removeDefaultArgument ( ) ;
return true ;
}
2014-08-06 03:39:34 +04:00
bool VisitDecl ( Decl * D ) {
2014-08-06 14:52:20 +04:00
if ( m_IsStoringState )
return true ;
2014-08-08 14:44:32 +04:00
if ( ! D - > hasAttr < AnnotateAttr > ( ) )
return false ;
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.
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-08 14:45:02 +04:00
bool TraverseTemplateDecl ( TemplateDecl * D ) {
if ( ! D - > getTemplatedDecl ( ) - > hasAttr < AnnotateAttr > ( ) )
return false ;
for ( auto P : D - > getTemplateParameters ( ) - > asArray ( ) )
TraverseDecl ( P ) ;
return true ;
}
2014-08-06 14:52:20 +04:00
bool TraverseNonTypeTemplateParmDecl ( NonTypeTemplateParmDecl * D ) {
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-06 14:52:20 +04:00
bool TraverseParmVarDecl ( ParmVarDecl * D ) {
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-07-30 01:14:15 +04:00
assert ( File & & " Must have a valid File " ) ;
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-06 02:07:20 +04:00
DefaultArgVisitor 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
AutoloadCallback : : AutoloadCallback ( Interpreter * interp ) :
2014-07-12 22:23:55 +04:00
InterpreterCallbacks ( interp , true , false , true ) , m_Interpreter ( interp ) {
2014-07-22 20:30:30 +04:00
2014-06-08 01:52:32 +04:00
}
2014-08-05 23:37:15 +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-07-13 20:43:20 +04:00
2014-08-06 02:07:20 +04:00
DefaultArgVisitor defaultArgsStateCollector ;
2014-08-06 03:39:34 +04:00
Preprocessor & PP = m_Interpreter - > getCI ( ) - > getPreprocessor ( ) ;
2014-08-05 23:48:45 +04:00
for ( Transaction : : const_iterator I = T . decls_begin ( ) , E = T . decls_end ( ) ;
I ! = E ; + + I ) {
Transaction : : DelayCallInfo DCI = * I ;
2014-08-06 03:39:34 +04:00
// if (DCI.m_Call != Transaction::kCCIHandleTopLevelDecl)
// continue;
// if (DCI.m_DGR.isNull() || !(*DCI.m_DGR.begin())->hasAttr<AnnotateAttr>())
// continue;
2014-08-05 23:48:45 +04:00
for ( DeclGroupRef : : iterator J = DCI . m_DGR . begin ( ) ,
JE = DCI . m_DGR . end ( ) ; J ! = JE ; + + J ) {
2014-08-06 03:39:34 +04:00
defaultArgsStateCollector . TrackDefaultArgStateOf ( * J , m_Map , PP ) ;
2014-07-13 20:43:20 +04:00
}
2014-08-05 23:48:45 +04:00
}
2014-07-13 20:43:20 +04:00
}
2014-08-05 23:48:45 +04:00
} //end namespace cling