2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <libgen.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
|
|
|
|
#include "clang/AST/RecordLayout.h"
|
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
|
|
|
|
#include "TranslationUnitVisitor.hh"
|
|
|
|
#include "HeaderSearchDirs.hh"
|
|
|
|
#include "ClassTemplateVisitor.hh"
|
|
|
|
#include "ClassValues.hh"
|
|
|
|
#include "ClassVisitor.hh"
|
|
|
|
#include "EnumValues.hh"
|
|
|
|
#include "EnumVisitor.hh"
|
|
|
|
#include "TypedefVisitor.hh"
|
|
|
|
#include "VariableVisitor.hh"
|
|
|
|
#include "Utilities.hh"
|
|
|
|
#include "PrintAttributes.hh"
|
2017-01-23 23:48:16 +00:00
|
|
|
#include "BraceMacro.hh"
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
TranslationUnitVisitor::TranslationUnitVisitor(clang::CompilerInstance & in_ci , HeaderSearchDirs & in_hsd ,
|
|
|
|
CommentSaver & in_cs , PrintAttributes & in_pa ) :
|
|
|
|
ci(in_ci) , hsd(in_hsd) , cs(in_cs) , pa(in_pa) {}
|
|
|
|
|
|
|
|
bool TranslationUnitVisitor::TraverseDecl(clang::Decl *d) {
|
|
|
|
if (!d)
|
|
|
|
return true;
|
|
|
|
if (d->isImplicit())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
//std::cout << "\nTranslationUnitVisitor " << d->getDeclKindName() << std::endl ;
|
|
|
|
//d->dump() ;
|
|
|
|
|
|
|
|
switch ( d->getKind() ) {
|
|
|
|
case clang::Decl::TranslationUnit : {
|
|
|
|
TraverseTranslationUnitDecl(static_cast<clang::TranslationUnitDecl *>(d)) ;
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
case clang::Decl::CXXRecord : {
|
|
|
|
clang::CXXRecordDecl * crd = static_cast<clang::CXXRecordDecl *>(d) ;
|
|
|
|
/* The definition of the record must exist before we can process it. The definition is
|
|
|
|
NULL when this is only a forward declaration of a class */
|
|
|
|
/* Sometimes rd is not NULL when we still only have a forward declaration because
|
|
|
|
the file that defines the class is included before processing this fwd declare.
|
|
|
|
In this case the CXXRecordDecl file name will not match the current file name, and is
|
|
|
|
in fact empty */
|
|
|
|
clang::RecordDecl * rd = crd->getDefinition() ;
|
2016-10-28 18:21:21 +00:00
|
|
|
if ( rd != NULL ) {
|
2017-01-23 23:48:16 +00:00
|
|
|
std::string rd_file = getFileName(ci , rd->RBRACELOC(), hsd) ;
|
|
|
|
std::string crd_file = getFileName(ci , crd->RBRACELOC(), hsd) ;
|
2016-10-28 18:21:21 +00:00
|
|
|
if (!crd_file.empty() and !crd_file.compare(rd_file)) {
|
|
|
|
//crd->dump() ; std::cout << std::endl ;
|
2017-01-23 23:48:16 +00:00
|
|
|
if ( isInUserCode(ci , crd->RBRACELOC(), hsd) ) {
|
2016-10-28 18:21:21 +00:00
|
|
|
CXXRecordVisitor cvis(ci , cs, hsd , pa, true) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
2016-10-28 18:21:21 +00:00
|
|
|
cvis.TraverseCXXRecordDecl(static_cast<clang::CXXRecordDecl *>(d)) ;
|
|
|
|
pa.printClass(cvis.get_class_data()) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
2016-10-28 18:21:21 +00:00
|
|
|
/* Check to see if the struct/class is forward declared in the same file.
|
|
|
|
If it is, then remove the notation that it is forward declared. This
|
|
|
|
is to allow C structs to be forward declared and typedeffed and io_src
|
|
|
|
code will be generated for both the original structure name and typedeffed
|
|
|
|
name.
|
2015-02-26 15:02:31 +00:00
|
|
|
|
2016-10-28 18:21:21 +00:00
|
|
|
struct Astruct ;
|
|
|
|
typedef struct Astruct {} Bstruct ;
|
|
|
|
*/
|
|
|
|
std::set< std::string >::iterator it ;
|
|
|
|
std::string file_name = getFileName(ci , d->getLocEnd(), hsd) ;
|
|
|
|
std::string source_type = cvis.get_class_data()->getName() ;
|
|
|
|
it = fwd_declared_classes[file_name].find(source_type) ;
|
|
|
|
if ( it != fwd_declared_classes[file_name].end() ) {
|
|
|
|
fwd_declared_classes[file_name].erase(it) ;
|
|
|
|
}
|
2015-02-26 15:02:31 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// These are forward declarations. Insert this into the set of fwd declares keyed by the current file.
|
|
|
|
if ( ! crd->getNameAsString().empty() ) {
|
|
|
|
fwd_declared_classes[getFileName(ci , d->getLocEnd(), hsd)].insert(crd->getNameAsString()) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
case clang::Decl::Enum : {
|
|
|
|
clang::EnumDecl * ed = static_cast<clang::EnumDecl *>(d) ;
|
2017-01-23 23:48:16 +00:00
|
|
|
if ( isInUserCode(ci , ed->RBRACELOC(), hsd) ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
EnumVisitor evis(ci, hsd) ;
|
|
|
|
evis.TraverseDecl(ed) ;
|
|
|
|
//if ( evis.get_enum_data() != NULL ) {
|
|
|
|
pa.printEnum(evis.get_enum_data()) ;
|
|
|
|
//}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
case clang::Decl::LinkageSpec : {
|
|
|
|
// This is an extern "C" block, traverse the node and the contents within the extern "C" block.
|
|
|
|
TraverseLinkageSpecDecl(static_cast<clang::LinkageSpecDecl *>(d)) ;
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
case clang::Decl::Namespace : {
|
|
|
|
TraverseNamespaceDecl(static_cast<clang::NamespaceDecl *>(d)) ;
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
case clang::Decl::ClassTemplate : {
|
|
|
|
clang::ClassTemplateDecl * ctd = static_cast<clang::ClassTemplateDecl *>(d) ;
|
|
|
|
if ( isInUserCode(ci, ctd->getSourceRange().getBegin(), hsd) ) {
|
|
|
|
clang::CXXRecordDecl * rd = ctd->getTemplatedDecl() ;
|
|
|
|
ClassTemplateVisitor ctvis(ci, cs, hsd, pa) ;
|
|
|
|
ctvis.TraverseDecl(rd) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
case clang::Decl::Typedef : {
|
|
|
|
clang::TypedefDecl * td = static_cast<clang::TypedefDecl *>(d) ;
|
|
|
|
if ( isInUserCode(ci, td->getSourceRange().getBegin(), hsd) ) {
|
|
|
|
TypedefVisitor tv(ci , cs, hsd, pa, fwd_declared_classes[getFileName(ci , d->getLocEnd(), hsd)]) ;
|
|
|
|
tv.TraverseDecl(d) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
case clang::Decl::Var : {
|
|
|
|
if ( isInUserCode(ci, d->getSourceRange().getBegin(), hsd) ) {
|
|
|
|
VariableVisitor tv(ci , cs, hsd, pa, fwd_declared_classes[getFileName(ci , d->getLocEnd(), hsd)]) ;
|
|
|
|
tv.TraverseDecl(d) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break ;
|
|
|
|
default :
|
|
|
|
break ;
|
|
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|