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"
2016-09-10 22:04:39 +03:00
# include "cling/Utils/Output.h"
2016-09-30 00:16:27 +03:00
# include "cling/Utils/Platform.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"
2016-04-22 16:11:37 +03:00
# include "clang/Basic/TargetInfo.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/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
using namespace clang ;
namespace cling {
2013-10-29 13:43:48 +04:00
2016-09-30 08:02:42 +03:00
ClangInternalState : : ClangInternalState ( const ASTContext & AC ,
const Preprocessor & PP ,
const 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 ) ,
2020-10-05 09:22:33 +03:00
# if defined(_WIN32)
2016-09-30 00:16:27 +03:00
m_DiffCommand ( " diff.exe -u --text " ) ,
# else
m_DiffCommand ( " diff -u --text " ) ,
# endif
m_Name ( name ) , m_DiffPair ( nullptr ) {
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)
2014-08-14 14:29:27 +04:00
std : : unique_ptr < llvm : : raw_fd_ostream > m_LookupTablesOS ;
std : : unique_ptr < llvm : : raw_fd_ostream > m_IncludedFilesOS ;
std : : unique_ptr < llvm : : raw_fd_ostream > m_ASTOS ;
std : : unique_ptr < llvm : : raw_fd_ostream > m_LLVMModuleOS ;
std : : unique_ptr < 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*/ ) {
2014-08-14 14:29:27 +04:00
std : : unique_ptr < llvm : : raw_fd_ostream > OS ;
2013-09-17 18:34:41 +04:00
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 ) ) ;
2021-09-11 21:12:30 +03:00
OSFile = TempPath . str ( ) . str ( ) ;
2013-09-17 18:34:41 +04:00
}
// 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
2014-08-14 14:29:27 +04:00
return OS . release ( ) ;
2013-09-17 18:34:41 +04:00
}
2016-09-30 07:58:04 +03:00
void ClangInternalState : : compare ( const std : : string & name , bool verbose ) {
2014-02-03 22:14:48 +04:00
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
2016-10-04 21:41:27 +03:00
llvm : : SmallVector < llvm : : StringRef , 1024 > builtinNames ;
2016-04-22 16:11:37 +03:00
const clang : : Builtin : : Context & BuiltinCtx = m_ASTContext . BuiltinInfo ;
2016-10-04 21:41:27 +03:00
for ( auto i = clang : : Builtin : : NotBuiltin + 1 ;
2016-04-22 16:11:37 +03:00
i ! = clang : : Builtin : : FirstTSBuiltin ; + + i ) {
2016-10-04 21:41:27 +03:00
llvm : : StringRef Name ( BuiltinCtx . getName ( i ) ) ;
if ( Name . startswith ( " __builtin " ) )
builtinNames . emplace_back ( Name ) ;
2016-04-22 16:11:37 +03:00
}
for ( auto & & BuiltinInfo : m_ASTContext . getTargetInfo ( ) . getTargetBuiltins ( ) ) {
2016-10-04 21:41:27 +03:00
llvm : : StringRef Name ( BuiltinInfo . Name ) ;
if ( ! Name . startswith ( " __builtin " ) )
builtinNames . emplace_back ( Name ) ;
# ifndef NDEBUG
else // Make sure it's already in the list
assert ( std : : find ( builtinNames . begin ( ) , builtinNames . end ( ) ,
Name ) = = builtinNames . end ( ) & & " Not in list! " ) ;
# endif
2013-10-14 18:30:40 +04:00
}
2014-01-30 17:00:43 +04:00
builtinNames . push_back ( " .*__builtin.* " ) ;
2016-09-30 00:16:27 +03:00
differentContent ( m_LookupTablesFile , m_DiffPair - > m_LookupTablesFile ,
2016-09-30 07:58:04 +03:00
" lookup tables " , verbose , & builtinNames ) ;
2016-09-30 00:16:27 +03:00
2017-05-18 18:36:41 +03:00
// We create a virtual file for each input line in the format input_line_N.
llvm : : SmallVector < llvm : : StringRef , 2 > input_lines ;
input_lines . push_back ( " input_line_[0-9].* " ) ;
2016-09-30 00:16:27 +03:00
differentContent ( m_IncludedFilesFile , m_DiffPair - > m_IncludedFilesFile ,
2017-05-18 18:36:41 +03:00
" included files " , verbose , & input_lines ) ;
2016-09-30 00:16:27 +03:00
2016-09-30 07:58:04 +03:00
differentContent ( m_ASTFile , m_DiffPair - > m_ASTFile , " AST " , verbose ) ;
2016-09-30 00:16:27 +03:00
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 ( ) ;
2016-10-04 21:41:27 +03:00
for ( const auto & Func : m_Module - > getFunctionList ( ) ) {
if ( Func . isIntrinsic ( ) )
builtinNames . emplace_back ( Func . getName ( ) ) ;
}
2016-09-30 00:16:27 +03:00
differentContent ( m_LLVMModuleFile , m_DiffPair - > m_LLVMModuleFile ,
2016-09-30 07:58:04 +03:00
" llvm Module " , verbose , & builtinNames ) ;
2013-10-22 14:18:54 +04:00
}
2016-09-30 00:16:27 +03:00
differentContent ( m_MacrosFile , m_DiffPair - > m_MacrosFile ,
2016-09-30 07:58:04 +03:00
" Macro Definitions " , verbose ) ;
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 ,
2016-09-30 00:16:27 +03:00
const char * type ,
2016-09-30 07:58:04 +03:00
bool verbose ,
2016-10-04 21:41:27 +03:00
const llvm : : SmallVectorImpl < llvm : : StringRef > * ignores /*=0*/ ) const {
2016-09-30 00:16:27 +03:00
2013-10-14 18:30:40 +04:00
std : : string diffCall = m_DiffCommand ;
if ( ignores ) {
2016-10-04 21:41:27 +03:00
for ( const llvm : : StringRef & ignore : * ignores ) {
2013-10-14 18:30:40 +04:00
diffCall + = " --ignore-matching-lines= \" .* " ;
2016-10-04 21:41:27 +03:00
diffCall + = ignore ;
2013-10-14 18:30:40 +04:00
diffCall + = " .* \" " ;
}
}
2016-09-30 00:16:27 +03:00
diffCall + = " " ;
diffCall + = file1 ;
diffCall + = " " ;
diffCall + = file2 ;
2013-10-14 18:30:40 +04:00
2016-09-30 00:16:27 +03:00
llvm : : SmallString < 1024 > Difs ;
platform : : Popen ( diffCall , Difs ) ;
2013-12-05 18:35:27 +04:00
2016-09-30 07:58:04 +03:00
if ( verbose )
2016-09-10 22:04:39 +03:00
cling : : log ( ) < < diffCall < < " \n " ;
2016-09-30 07:58:04 +03:00
2016-09-30 00:16:27 +03:00
if ( Difs . empty ( ) )
return false ;
2013-12-05 18:35:27 +04:00
2016-09-30 00:16:27 +03:00
if ( type ) {
2016-09-10 22:04:39 +03:00
cling : : log ( ) < < " Differences in the " < < type < < " : \n " ;
cling : : log ( ) < < Difs < < " \n " ;
2016-09-30 00:16:27 +03:00
}
return true ;
2013-09-17 18:34:41 +04:00
}
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 ,
2016-09-30 08:02:42 +03:00
const ASTContext & C ) {
2013-09-17 18:34:41 +04:00
DumpLookupTables dumper ( Out ) ;
dumper . TraverseDecl ( C . getTranslationUnitDecl ( ) ) ;
}
2014-01-30 17:00:43 +04:00
void ClangInternalState : : printIncludedFiles ( llvm : : raw_ostream & Out ,
2016-09-30 08:02:42 +03:00
const SourceManager & SM ) {
2017-06-09 13:37:59 +03:00
// FileInfos are stored as a mapping, and invalidating the cache
// can change iteration order.
std : : vector < std : : string > ParsedOpen , Parsed , AST ;
2013-09-17 18:34:41 +04:00
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 & &
2014-10-20 16:16:34 +04:00
fileName . find ( " /bits/ " ) ! = std : : string : : npos ) & &
fileName . compare ( " - " ) ) {
2021-09-11 23:22:31 +03:00
if ( I - > second - > getBufferDataIfLoaded ( ) ) {
2014-10-20 16:16:34 +04:00
// There is content - a memory buffer or a file.
// We know it's a file because we started off the FileEntry.
if ( FE - > isOpen ( ) )
2017-06-09 13:37:59 +03:00
ParsedOpen . emplace_back ( std : : move ( fileName ) ) ;
2014-10-20 16:16:34 +04:00
else
2017-06-09 13:37:59 +03:00
Parsed . emplace_back ( std : : move ( fileName ) ) ;
2014-10-20 16:16:34 +04:00
} else
2017-06-09 13:37:59 +03:00
AST . emplace_back ( std : : move ( fileName ) ) ;
2013-09-17 19:09:27 +04:00
}
2013-09-17 18:34:41 +04:00
}
2017-06-09 13:37:59 +03:00
auto DumpFiles = [ & Out ] ( const char * What , std : : vector < std : : string > & Files ) {
if ( Files . empty ( ) )
return ;
Out < < What < < " : \n " ;
std : : sort ( Files . begin ( ) , Files . end ( ) ) ;
for ( auto & & FileName : Files )
Out < < " " < < FileName < < ' \n ' ;
} ;
DumpFiles ( " Parsed and open " , ParsedOpen ) ;
DumpFiles ( " Parsed " , Parsed ) ;
DumpFiles ( " From AST file " , AST ) ;
2013-09-17 18:34:41 +04:00
}
2016-09-30 08:02:42 +03:00
void ClangInternalState : : printAST ( llvm : : raw_ostream & Out , const ASTContext & C ) {
2013-09-17 18:34:41 +04:00
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 ,
2016-09-30 08:02:42 +03:00
const llvm : : Module & M ,
2014-02-27 18:51:37 +04:00
CodeGenerator & CG ) {
2022-09-13 09:34:32 +03:00
M . print ( Out , /*AssemblyAnnotationWriter*/ nullptr ) ;
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 ,
2016-09-30 08:02:42 +03:00
const clang : : Preprocessor & PP ) {
2016-12-14 23:32:18 +03:00
stdstrstream contentsOS ;
2014-02-07 18:08:29 +04:00
PP . printMacros ( contentsOS ) ;
Out < < " Ordered Alphabetically: \n " ;
std : : vector < std : : string > elems ;
{
// Split the string into lines.
char delim = ' \n ' ;
2016-12-14 23:32:18 +03:00
std : : stringstream ss ( contentsOS . str ( ) ) ;
2014-02-07 18:08:29 +04:00
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