2013-09-17 18:34:41 +04:00
//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// author: Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
2014-01-07 14:08:37 +04: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.
2013-09-17 18:34:41 +04:00
//------------------------------------------------------------------------------
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"
2014-02-27 18:51:37 +04:00
# include "clang/CodeGen/ModuleBuilder.h"
2013-09-17 18:34:41 +04:00
# 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>
2014-02-07 18:08:29 +04:00
# include <sstream>
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
2013-12-04 13:58:47 +04:00
# ifdef WIN32
# define popen _popen
# define pclose _pclose
# endif
2013-09-17 18:34:41 +04:00
using namespace clang ;
namespace cling {
2013-10-29 13:43:48 +04:00
2013-10-25 17:22:45 +04:00
ClangInternalState : : ClangInternalState ( ASTContext & AC , Preprocessor & PP ,
2014-02-27 18:51:37 +04:00
llvm : : Module * M , CodeGenerator * CG ,
2014-02-03 22:14:48 +04:00
const std : : string & name )
2014-03-03 14:50:25 +04:00
: m_ASTContext ( AC ) , m_Preprocessor ( PP ) , m_CodeGen ( CG ) , m_Module ( M ) ,
2014-02-03 22:14:48 +04:00
m_DiffCommand ( " diff -u --text " ) , m_Name ( name ) , m_DiffPair ( 0 ) {
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-12-05 18:34:51 +04:00
// Cannot use the stack (private copy ctor)
llvm : : OwningPtr < llvm : : raw_fd_ostream > m_LookupTablesOS ;
llvm : : OwningPtr < llvm : : raw_fd_ostream > m_IncludedFilesOS ;
llvm : : OwningPtr < llvm : : raw_fd_ostream > m_ASTOS ;
llvm : : OwningPtr < llvm : : raw_fd_ostream > m_LLVMModuleOS ;
llvm : : OwningPtr < llvm : : raw_fd_ostream > m_MacrosOS ;
2013-10-21 19:31:21 +04:00
2013-11-15 18:18:57 +04:00
m_LookupTablesOS . reset ( createOutputFile ( " lookup " ,
& m_LookupTablesFile ) ) ;
m_IncludedFilesOS . reset ( createOutputFile ( " included " ,
& m_IncludedFilesFile ) ) ;
2013-10-21 19:31:21 +04:00
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 ) ;
2014-01-29 18:23:49 +04:00
printIncludedFiles ( * m_IncludedFilesOS . get ( ) ,
2013-09-17 18:34:41 +04:00
m_ASTContext . getSourceManager ( ) ) ;
printAST ( * m_ASTOS . get ( ) , m_ASTContext ) ;
2014-01-29 18:23:49 +04:00
if ( m_Module )
2014-02-27 18:51:37 +04:00
printLLVMModule ( * m_LLVMModuleOS . get ( ) , * m_Module , * m_CodeGen ) ;
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
2014-01-30 17:00:43 +04:00
llvm : : raw_fd_ostream *
2013-09-17 18:34:41 +04:00
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.
2014-02-03 22:12:58 +04:00
llvm : : sys : : path : : append ( TempPath , " cling- " + 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 )
2014-08-01 16:04:18 +04:00
! = std : : errc : : no_such_file_or_directory ) {
2013-09-17 18:34:41 +04:00
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 ( ) ;
}
2014-02-03 22:14:48 +04:00
void ClangInternalState : : compare ( const std : : string & name ) {
assert ( name = = m_Name & & " Different names!? " ) ;
m_DiffPair . reset ( new ClangInternalState ( m_ASTContext , m_Preprocessor ,
2014-02-27 18:51:37 +04:00
m_Module , m_CodeGen , name ) ) ;
2013-09-17 18:34:41 +04:00
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 ) ;
2014-01-30 17:00:43 +04:00
for ( Builtins : : iterator I = builtinNames . begin ( ) ;
2013-10-14 18:30:40 +04:00
I ! = builtinNames . end ( ) ; ) {
if ( llvm : : StringRef ( * I ) . startswith ( " __builtin " ) )
I = builtinNames . erase ( I ) ;
else
+ + I ;
}
2014-01-30 17:00:43 +04:00
builtinNames . push_back ( " .*__builtin.* " ) ;
2014-02-03 22:14:48 +04:00
if ( differentContent ( m_LookupTablesFile , m_DiffPair - > 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 = " " ;
}
2014-02-03 22:14:48 +04:00
if ( differentContent ( m_IncludedFilesFile , m_DiffPair - > m_IncludedFilesFile ,
2013-09-17 18:34:41 +04:00
differences ) ) {
llvm : : errs ( ) < < " Differences in the included files \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
2014-02-03 22:14:48 +04:00
if ( differentContent ( m_ASTFile , m_DiffPair - > m_ASTFile , differences ) ) {
2013-09-17 18:34:41 +04:00
llvm : : errs ( ) < < " Differences in the AST \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
2014-02-12 12:48:10 +04:00
if ( m_Module ) {
2014-02-27 18:51:37 +04:00
assert ( m_CodeGen & & " Must have CodeGen set " ) ;
2014-02-12 12:48:10 +04:00
// We want to skip the intrinsics
builtinNames . clear ( ) ;
for ( llvm : : Module : : const_iterator I = m_Module - > begin ( ) ,
E = m_Module - > end ( ) ; I ! = E ; + + I )
if ( I - > isIntrinsic ( ) )
builtinNames . push_back ( I - > getName ( ) . data ( ) ) ;
if ( differentContent ( m_LLVMModuleFile , m_DiffPair - > m_LLVMModuleFile ,
differences , & builtinNames ) ) {
llvm : : errs ( ) < < " Differences in the llvm Module \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
2013-10-09 17:28:06 +04:00
}
2014-02-03 22:14:48 +04:00
if ( differentContent ( m_MacrosFile , m_DiffPair - > m_MacrosFile , differences ) ) {
2013-10-22 14:18:54 +04:00
llvm : : errs ( ) < < " Differences in the Macro Definitions \n " ;
llvm : : errs ( ) < < differences < < " \n " ;
differences = " " ;
}
2013-09-17 18:34:41 +04:00
}
2014-01-30 17:00:43 +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 ) ;
2013-12-05 18:35:27 +04:00
if ( ! differences . empty ( ) )
llvm : : errs ( ) < < diffCall < < " " < < file1 < < " " < < file2 < < " \n " ;
2013-09-17 18:34:41 +04:00
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-12-05 18:36:19 +04:00
// If the lookup is pending for building, force its creation.
if ( DC = = DC - > getPrimaryContext ( ) & & ! DC - > getLookupPtr ( ) )
DC - > buildLookup ( ) ;
2013-10-14 16:31:55 +04:00
DC - > dumpLookups ( m_OS ) ;
2013-09-17 18:34:41 +04:00
return true ;
}
} ;
2014-01-30 17:00:43 +04:00
void ClangInternalState : : printLookupTables ( llvm : : raw_ostream & Out ,
2013-09-17 18:34:41 +04:00
ASTContext & C ) {
DumpLookupTables dumper ( Out ) ;
dumper . TraverseDecl ( C . getTranslationUnitDecl ( ) ) ;
}
2014-01-30 17:00:43 +04:00
void ClangInternalState : : printIncludedFiles ( llvm : : raw_ostream & Out ,
2013-09-17 18:34:41 +04:00
SourceManager & SM ) {
for ( clang : : SourceManager : : fileinfo_iterator I = SM . fileinfo_begin ( ) ,
E = SM . fileinfo_end ( ) ; I ! = E ; + + I ) {
2014-03-18 17:55:01 +04:00
const clang : : FileEntry * FE = I - > first ;
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.
2014-03-18 17:55:01 +04:00
if ( ! I - > second )
2013-10-16 16:27:26 +04:00
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
2014-01-30 17:00:43 +04:00
void ClangInternalState : : printLLVMModule ( llvm : : raw_ostream & Out ,
2014-02-27 18:51:37 +04:00
llvm : : Module & M ,
CodeGenerator & CG ) {
2013-10-09 17:28:06 +04:00
M . print ( Out , /*AssemblyAnnotationWriter*/ 0 ) ;
2014-02-27 18:51:37 +04:00
CG . print ( Out ) ;
2013-10-09 17:28:06 +04:00
}
2013-10-21 19:31:21 +04:00
void ClangInternalState : : printMacroDefinitions ( llvm : : raw_ostream & Out ,
clang : : Preprocessor & PP ) {
2014-02-07 18:08:29 +04:00
std : : string contents ;
llvm : : raw_string_ostream contentsOS ( contents ) ;
PP . printMacros ( contentsOS ) ;
contentsOS . flush ( ) ;
Out < < " Ordered Alphabetically: \n " ;
std : : vector < std : : string > elems ;
{
// Split the string into lines.
char delim = ' \n ' ;
std : : stringstream ss ( contents ) ;
std : : string item ;
while ( std : : getline ( ss , item , delim ) ) {
elems . push_back ( item ) ;
}
// Sort them alphabetically
std : : sort ( elems . begin ( ) , elems . end ( ) ) ;
}
2014-08-04 06:05:42 +04:00
for ( std : : vector < std : : string > : : iterator I = elems . begin ( ) ,
2014-02-07 18:08:29 +04:00
E = elems . end ( ) ; I ! = E ; + + I )
Out < < * I < < ' \n ' ;
Out . flush ( ) ;
2013-10-21 19:31:21 +04:00
}
2013-09-17 18:34:41 +04:00
} // end namespace cling