2013-09-17 18:34:41 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------
2013-09-17 19:13:38 +04:00
# include "cling/Interpreter/ClangInternalState.h"
2013-09-17 18:34:41 +04:00
# include "clang/AST/ASTContext.h"
2013-10-21 19:31:21 +04:00
# include "clang/Lex/Preprocessor.h"
2013-09-17 18:34:41 +04:00
# include "clang/AST/RecursiveASTVisitor.h"
2013-10-14 18:30:40 +04:00
# include "clang/Basic/Builtins.h"
2013-09-17 18:34:41 +04:00
# include "clang/Basic/SourceManager.h"
# include "llvm/ADT/SmallString.h"
2013-10-09 17:28:06 +04:00
# include "llvm/IR/Module.h"
2013-09-17 18:34:41 +04:00
# include "llvm/Support/FileSystem.h"
# include "llvm/Support/Path.h"
# include "llvm/Support/raw_ostream.h"
# include "llvm/Support/Signals.h"
2013-09-20 12:22:44 +04:00
# include <cstdio>
2013-09-17 18:34:41 +04:00
# include <string>
2013-10-09 17:25:00 +04:00
# include <time.h>
2013-09-17 18:34:41 +04:00
using namespace clang ;
namespace cling {
2013-10-21 19:31:21 +04:00
/*ClangInternalState::ClangInternalState(ASTContext& C, llvm::Module& M,
2013-10-09 17:28:06 +04:00
const std : : string & name )
2013-10-21 19:31:21 +04:00
: m_Preprocessor ( 0 ) , m_ASTContext ( C ) , m_Module ( M ) , m_DiffCommand ( " diff -u " ) , m_Name ( name ) {
store ( ) ;
} */
ClangInternalState : : ClangInternalState ( ASTContext & C , Preprocessor & PP , llvm : : Module & M ,
const std : : string & name )
: m_ASTContext ( C ) , m_Preprocessor ( PP ) , m_Module ( M ) , m_DiffCommand ( " diff -u " )
, m_Name ( name ) {
2013-09-17 18:34:41 +04:00
store ( ) ;
}
2013-09-20 12:22:44 +04:00
ClangInternalState : : ~ ClangInternalState ( ) {
// cleanup the temporary files:
remove ( m_LookupTablesFile . c_str ( ) ) ;
remove ( m_IncludedFilesFile . c_str ( ) ) ;
remove ( m_ASTFile . c_str ( ) ) ;
2013-10-09 17:28:06 +04:00
remove ( m_LLVMModuleFile . c_str ( ) ) ;
2013-10-21 19:31:21 +04:00
remove ( m_MacrosFile . c_str ( ) ) ;
2013-09-20 12:22:44 +04:00
}
2013-09-17 18:34:41 +04:00
void ClangInternalState : : store ( ) {
2013-10-21 19:31:21 +04:00
m_LookupTablesOS . reset ( createOutputFile ( " lookup " , & m_LookupTablesFile ) ) ;
m_IncludedFilesOS . reset ( createOutputFile ( " included " , & m_IncludedFilesFile ) ) ;
m_ASTOS . reset ( createOutputFile ( " ast " , & m_ASTFile ) ) ;
m_LLVMModuleOS . reset ( createOutputFile ( " module " , & m_LLVMModuleFile ) ) ;
m_MacrosOS . reset ( createOutputFile ( " macros " , & m_MacrosFile ) ) ;
2013-09-17 18:34:41 +04:00
printLookupTables ( * m_LookupTablesOS . get ( ) , m_ASTContext ) ;
printIncludedFiles ( * m_IncludedFilesOS . get ( ) ,
m_ASTContext . getSourceManager ( ) ) ;
printAST ( * m_ASTOS . get ( ) , m_ASTContext ) ;
2013-10-09 17:28:06 +04:00
printLLVMModule ( * m_LLVMModuleOS . get ( ) , m_Module ) ;
2013-10-21 19:31:21 +04:00
printMacroDefinitions ( * m_MacrosOS . get ( ) , m_Preprocessor ) ;
2013-09-17 18:34:41 +04:00
}
2013-10-09 17:25:00 +04:00
namespace {
std : : string getCurrentTimeAsString ( ) {
time_t rawtime ;
struct tm * timeinfo ;
char buffer [ 80 ] ;
time ( & rawtime ) ;
timeinfo = localtime ( & rawtime ) ;
strftime ( buffer , 80 , " %I_%M_%S " , timeinfo ) ;
return buffer ;
}
}
2013-09-17 18:34:41 +04:00
// Copied with modifications from CompilerInstance.cpp
llvm : : raw_fd_ostream *
ClangInternalState : : createOutputFile ( llvm : : StringRef OutFile ,
std : : string * TempPathName /*=0*/ ,
bool RemoveFileOnSignal /*=true*/ ) {
llvm : : OwningPtr < llvm : : raw_fd_ostream > OS ;
std : : string OSFile ;
llvm : : SmallString < 256 > OutputPath ;
llvm : : sys : : path : : system_temp_directory ( /*erasedOnReboot*/ false , OutputPath ) ;
// Only create the temporary if the parent directory exists (or create
// missing directories is true) and we can actually write to OutPath,
// otherwise we want to fail early.
2013-09-23 17:16:55 +04:00
llvm : : SmallString < 256 > TempPath ( OutputPath ) ;
llvm : : sys : : fs : : make_absolute ( TempPath ) ;
2013-09-24 17:25:48 +04:00
assert ( llvm : : sys : : fs : : is_directory ( TempPath . str ( ) ) & & " Must be a folder. " ) ;
2013-09-17 18:34:41 +04:00
// Create a temporary file.
2013-10-01 16:17:22 +04:00
llvm : : sys : : path : : append ( TempPath , OutFile ) ;
2013-10-09 17:25:00 +04:00
TempPath + = " - " + getCurrentTimeAsString ( ) ;
2013-09-17 18:34:41 +04:00
TempPath + = " -%%%%%%%% " ;
int fd ;
2013-09-23 17:16:55 +04:00
if ( llvm : : sys : : fs : : createUniqueFile ( TempPath . str ( ) , fd , TempPath )
2013-09-17 18:34:41 +04:00
= = llvm : : errc : : success ) {
OS . reset ( new llvm : : raw_fd_ostream ( fd , /*shouldClose=*/ true ) ) ;
OSFile = TempPath . str ( ) ;
}
// Make sure the out stream file gets removed if we crash.
if ( RemoveFileOnSignal )
2013-09-23 17:16:55 +04:00
llvm : : sys : : RemoveFileOnSignal ( OSFile ) ;
2013-09-17 18:34:41 +04:00
if ( TempPathName )
* TempPathName = OSFile ;
2013-09-23 17:16:55 +04:00
2013-09-17 18:34:41 +04:00
return OS . take ( ) ;
}
void ClangInternalState : : compare ( ClangInternalState & other ) {
std : : string differences = " " ;
2013-10-14 18:30:40 +04:00
// Ignore the builtins
typedef llvm : : SmallVector < const char * , 1024 > Builtins ;
Builtins builtinNames ;
m_ASTContext . BuiltinInfo . GetBuiltinNames ( builtinNames ) ;
for ( Builtins : : iterator I = builtinNames . begin ( ) ;
I ! = builtinNames . end ( ) ; ) {
if ( llvm : : StringRef ( * I ) . startswith ( " __builtin " ) )
I = builtinNames . erase ( I ) ;
else
+ + I ;
}
builtinNames . push_back ( " .*__builtin.* " ) ;
2013-09-17 18:34:41 +04:00
if ( differentContent ( m_LookupTablesFile , other . m_LookupTablesFile ,
2013-10-14 18:30:40 +04:00
differences , & builtinNames ) ) {
2013-10-14 16:31:34 +04:00
llvm : : errs ( ) < < " Differences in the lookup tables \n " ;
2013-09-17 18:34:41 +04:00
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
if ( differentContent ( m_IncludedFilesFile , other . m_IncludedFilesFile ,
differences ) ) {
llvm : : errs ( ) < < " Differences in the included files \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
if ( differentContent ( m_ASTFile , other . m_ASTFile , differences ) ) {
llvm : : errs ( ) < < " Differences in the AST \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
2013-10-09 17:28:06 +04:00
if ( differentContent ( m_LLVMModuleFile , other . m_LLVMModuleFile , differences ) ) {
llvm : : errs ( ) < < " Differences in the llvm Module \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
2013-10-22 14:18:54 +04:00
if ( differentContent ( m_MacrosFile , other . m_MacrosFile , differences ) ) {
llvm : : errs ( ) < < " Differences in the Macro Definitions \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
2013-09-17 18:34:41 +04:00
}
bool ClangInternalState : : differentContent ( const std : : string & file1 ,
const std : : string & file2 ,
2013-10-14 18:30:40 +04:00
std : : string & differences ,
const llvm : : SmallVectorImpl < const char * > * ignores /*=0*/ ) const {
std : : string diffCall = m_DiffCommand ;
if ( ignores ) {
for ( size_t i = 0 , e = ignores - > size ( ) ; i < e ; + + i ) {
diffCall + = " --ignore-matching-lines= \" .* " ;
diffCall + = ( * ignores ) [ i ] ;
diffCall + = " .* \" " ;
}
}
FILE * pipe = popen ( ( diffCall + " " + file1 + " " + file2 ) . c_str ( ) , " r " ) ;
2013-09-17 18:34:41 +04:00
assert ( pipe & & " Error creating the pipe " ) ;
assert ( differences . empty ( ) & & " Must be empty " ) ;
char buffer [ 128 ] ;
while ( ! feof ( pipe ) ) {
if ( fgets ( buffer , 128 , pipe ) ! = NULL )
differences + = buffer ;
}
pclose ( pipe ) ;
return ! differences . empty ( ) ;
}
class DumpLookupTables : public RecursiveASTVisitor < DumpLookupTables > {
private :
2013-10-14 16:31:55 +04:00
llvm : : raw_ostream & m_OS ;
2013-09-17 18:34:41 +04:00
public :
2013-10-14 16:31:55 +04:00
DumpLookupTables ( llvm : : raw_ostream & OS ) : m_OS ( OS ) { }
bool VisitDecl ( Decl * D ) {
if ( DeclContext * DC = dyn_cast < DeclContext > ( D ) )
VisitDeclContext ( DC ) ;
return true ;
}
2013-09-17 18:34:41 +04:00
bool VisitDeclContext ( DeclContext * DC ) {
2013-10-14 16:31:55 +04:00
DC - > dumpLookups ( m_OS ) ;
2013-09-17 18:34:41 +04:00
return true ;
}
} ;
void ClangInternalState : : printLookupTables ( llvm : : raw_ostream & Out ,
ASTContext & C ) {
DumpLookupTables dumper ( Out ) ;
dumper . TraverseDecl ( C . getTranslationUnitDecl ( ) ) ;
}
void ClangInternalState : : printIncludedFiles ( llvm : : raw_ostream & Out ,
SourceManager & SM ) {
for ( clang : : SourceManager : : fileinfo_iterator I = SM . fileinfo_begin ( ) ,
E = SM . fileinfo_end ( ) ; I ! = E ; + + I ) {
const clang : : SrcMgr : : ContentCache & C = * I - > second ;
const clang : : FileEntry * FE = C . OrigEntry ;
2013-10-16 16:27:26 +04:00
// Our error recovery purges the cache of the FileEntry, but keeps
// the FileEntry's pointer so that if it was used by smb (like the
// SourceManager) it wouldn't be dangling. In that case we shouldn't
// print the FileName, because semantically it is not there.
if ( ! FE - > getSize ( ) & & ! FE - > getModificationTime ( ) )
continue ;
2013-09-17 18:34:41 +04:00
std : : string fileName ( FE - > getName ( ) ) ;
2013-09-17 19:09:27 +04:00
if ( ! ( fileName . compare ( 0 , 5 , " /usr/ " ) = = 0 & &
fileName . find ( " /bits/ " ) ! = std : : string : : npos ) ) {
Out < < fileName < < ' \n ' ;
}
2013-09-17 18:34:41 +04:00
}
}
void ClangInternalState : : printAST ( llvm : : raw_ostream & Out , ASTContext & C ) {
TranslationUnitDecl * TU = C . getTranslationUnitDecl ( ) ;
unsigned Indentation = 0 ;
bool PrintInstantiation = false ;
std : : string ErrMsg ;
clang : : PrintingPolicy policy = C . getPrintingPolicy ( ) ;
TU - > print ( Out , policy , Indentation , PrintInstantiation ) ;
2013-10-29 06:33:24 +04:00
// TODO: For future when we relpace the bump allocation with slab.
//
//Out << "Allocated memory: " << C.getAllocatedMemory();
//Out << "Side table allocated memory: " << C.getSideTableAllocatedMemory();
2013-09-17 18:34:41 +04:00
Out . flush ( ) ;
}
2013-10-09 17:28:06 +04:00
void ClangInternalState : : printLLVMModule ( llvm : : raw_ostream & Out ,
llvm : : Module & M ) {
M . print ( Out , /*AssemblyAnnotationWriter*/ 0 ) ;
}
2013-10-21 19:31:21 +04:00
void ClangInternalState : : printMacroDefinitions ( llvm : : raw_ostream & Out ,
clang : : Preprocessor & PP ) {
for ( clang : : Preprocessor : : macro_iterator I = PP . macro_begin ( ) ,
E = PP . macro_end ( ) ; I ! = E ; + + I ) {
2013-10-22 14:18:54 +04:00
Out < < ( * I ) . first - > getName ( ) < < ' \n ' ;
2013-10-21 19:31:21 +04:00
}
}
2013-09-17 18:34:41 +04:00
} // end namespace cling