2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "clang/AST/RecordLayout.h"
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
|
|
|
|
#include "FieldVisitor.hh"
|
|
|
|
#include "FieldDescription.hh"
|
|
|
|
#include "ClassValues.hh"
|
|
|
|
#include "EnumValues.hh"
|
|
|
|
#include "ClassVisitor.hh"
|
|
|
|
#include "CommentSaver.hh"
|
|
|
|
#include "Utilities.hh"
|
|
|
|
|
|
|
|
extern llvm::cl::opt< int > debug_level ;
|
|
|
|
|
|
|
|
FieldVisitor::FieldVisitor(clang::CompilerInstance & in_ci ,
|
|
|
|
HeaderSearchDirs & in_hsd ,
|
|
|
|
CommentSaver & in_cs ,
|
|
|
|
PrintAttributes & in_pa ,
|
|
|
|
std::string container_class ,
|
|
|
|
bool in_access_spec_found ,
|
|
|
|
bool in_inherited ,
|
|
|
|
bool in_virtual_inherited ,
|
|
|
|
unsigned int in_base_class_offset ) :
|
|
|
|
ci(in_ci) ,
|
|
|
|
hsd(in_hsd) ,
|
|
|
|
cs(in_cs) ,
|
|
|
|
pa(in_pa) {
|
|
|
|
fdes = new FieldDescription(container_class, in_access_spec_found, in_inherited, in_virtual_inherited, in_base_class_offset) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitDecl(clang::Decl *d) {
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "\nFieldVisitor Decl = " << d->getDeclKindName() << std::endl ;
|
|
|
|
d->dump() ;
|
|
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitType(clang::Type *t) {
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "\nFieldVisitor Type = " << t->getTypeClassName() << std::endl ;
|
|
|
|
t->dump() ;
|
|
|
|
}
|
|
|
|
// If this type is a reference, set IO to 0
|
|
|
|
if ( t->isReferenceType() ) {
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitType found reference, setIO = 0 " << std::endl ;
|
|
|
|
}
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitBuiltinType(clang::BuiltinType *bt) {
|
|
|
|
|
|
|
|
fdes->setTypeName(bt->desugar().getAsString()) ;
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor::VisitBuiltinType " << fdes->getTypeName() << std::endl ;
|
|
|
|
}
|
|
|
|
if ( fdes->isBitField() ) {
|
|
|
|
if ( bt->isUnsignedInteger() ) {
|
|
|
|
fdes->setEnumString("TRICK_UNSIGNED_BITFIELD") ;
|
|
|
|
} else {
|
|
|
|
fdes->setEnumString("TRICK_BITFIELD") ;
|
|
|
|
}
|
|
|
|
if ( bt->getKind() == clang::BuiltinType::Bool ) {
|
|
|
|
fdes->setTypeName("bool") ;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
switch ( bt->getKind() ) {
|
|
|
|
case clang::BuiltinType::Bool:
|
|
|
|
fdes->setEnumString("TRICK_BOOLEAN") ;
|
|
|
|
fdes->setTypeName("bool") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::Char_S:
|
|
|
|
case clang::BuiltinType::SChar:
|
|
|
|
fdes->setEnumString("TRICK_CHARACTER") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::UChar:
|
|
|
|
case clang::BuiltinType::Char_U:
|
|
|
|
fdes->setEnumString("TRICK_UNSIGNED_CHARACTER") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::WChar_U:
|
|
|
|
case clang::BuiltinType::WChar_S:
|
|
|
|
fdes->setEnumString("TRICK_WCHAR") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::Short:
|
|
|
|
fdes->setEnumString("TRICK_SHORT") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::UShort:
|
|
|
|
case clang::BuiltinType::Char16:
|
|
|
|
fdes->setEnumString("TRICK_UNSIGNED_SHORT") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::Int:
|
|
|
|
fdes->setEnumString("TRICK_INTEGER") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::UInt:
|
|
|
|
fdes->setEnumString("TRICK_UNSIGNED_INTEGER") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::Long:
|
|
|
|
fdes->setEnumString("TRICK_LONG") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::ULong:
|
|
|
|
fdes->setEnumString("TRICK_UNSIGNED_LONG") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::LongLong:
|
|
|
|
fdes->setEnumString("TRICK_LONG_LONG") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::ULongLong:
|
|
|
|
fdes->setEnumString("TRICK_UNSIGNED_LONG_LONG") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::Float:
|
|
|
|
fdes->setEnumString("TRICK_FLOAT") ;
|
|
|
|
break ;
|
|
|
|
case clang::BuiltinType::Double:
|
|
|
|
fdes->setEnumString("TRICK_DOUBLE") ;
|
|
|
|
break ;
|
|
|
|
default:
|
|
|
|
fdes->setEnumString("TRICK_VOID") ;
|
|
|
|
break ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitConstantArrayType(clang::ConstantArrayType *cat) {
|
|
|
|
//cat->dump() ; std::cout << std::endl ;
|
|
|
|
fdes->addArrayDim(cat->getSize().getZExtValue()) ;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Both FieldDecl and VarDecl derive from DeclaratorDecl. We can do
|
|
|
|
common things to both node types in this function */
|
|
|
|
bool FieldVisitor::VisitDeclaratorDecl( clang::DeclaratorDecl *dd ) {
|
|
|
|
|
|
|
|
fdes->setFileName(getFileName(ci , dd->getLocation(), hsd)) ;
|
|
|
|
fdes->setName(dd->getNameAsString()) ;
|
|
|
|
fdes->setAccess(dd->getAccess()) ;
|
|
|
|
|
|
|
|
/* Get the source location of this field. */
|
|
|
|
clang::SourceRange dd_range = dd->getSourceRange() ;
|
2015-06-10 19:19:00 +00:00
|
|
|
std::string file_name = ci.getSourceManager().getBufferName(dd_range.getEnd()) ;
|
|
|
|
if ( isInUserOrTrickCode( ci , dd_range.getEnd() , hsd ) ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
fdes->setLineNo(ci.getSourceManager().getSpellingLineNumber(dd_range.getEnd())) ;
|
|
|
|
/* process comment if neither ICG:(No) or ICG:(NoComment) is present */
|
2015-09-10 19:50:22 +00:00
|
|
|
if ( cs.hasTrickHeader(file_name) and
|
|
|
|
!cs.hasICGNoComment(file_name) and
|
|
|
|
!hsd.isPathInICGNoComment(file_name) ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
/* Get the possible comment on this line and parse it */
|
|
|
|
fdes->parseComment(cs.getComment(file_name , fdes->getLineNo())) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
if ( ! ci.getSourceManager().isInSystemHeader(dd_range.getEnd()) ) {
|
|
|
|
std::cout << "\nFieldVisitor VisitDeclaratorDecl" << std::endl ;
|
|
|
|
dd->dump() ; std::cout << std::endl ;
|
|
|
|
std::cout << " public/private = " << fdes->getAccess() << std::endl ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitEnumType( clang::EnumType *et ) {
|
|
|
|
|
|
|
|
std::string enum_type_name = et->desugar().getAsString() ;
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "\nFieldVisitor VisitEnumType" << std::endl ;
|
|
|
|
std::cout << et->desugar().getAsString() << std::endl ;
|
|
|
|
}
|
|
|
|
size_t pos ;
|
|
|
|
if ((pos = enum_type_name.find("enum ")) != std::string::npos ) {
|
|
|
|
enum_type_name.erase(pos , 5) ;
|
|
|
|
}
|
|
|
|
// If this enum is to an enumeration found inside a template, e.g. template<type>::enum_type ignore it.
|
|
|
|
// because there will not be enumeration attribute information generated for this enum.
|
|
|
|
if ((pos = enum_type_name.find("<")) != std::string::npos ) {
|
|
|
|
size_t last_pos = enum_type_name.find_last_of(">::") ;
|
|
|
|
enum_type_name.replace(pos, last_pos - pos + 1, "__") ;
|
|
|
|
//fdes->setIO(0) ;
|
|
|
|
}
|
|
|
|
fdes->setMangledTypeName("") ;
|
|
|
|
fdes->setTypeName(enum_type_name) ;
|
|
|
|
fdes->setEnumString("TRICK_ENUMERATED") ;
|
|
|
|
fdes->setEnum(true) ;
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitFieldDecl( clang::FieldDecl *field ) {
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "\nFieldVisitor VisitFieldDecl" << std::endl ;
|
|
|
|
field->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
fdes->setBitField(field->isBitField()) ;
|
|
|
|
if ( fdes->isBitField() ) {
|
|
|
|
fdes->setBitFieldWidth(field->getBitWidthValue(field->getASTContext())) ;
|
|
|
|
unsigned int field_offset_bits = field->getASTContext().getFieldOffset(field) + fdes->getBaseClassOffset() * 8 ;
|
|
|
|
fdes->setBitFieldStart( 32 - (field_offset_bits % 32) - fdes->getBitFieldWidth()) ;
|
|
|
|
fdes->setBitFieldByteOffset((field_offset_bits / 32) * 4 ) ;
|
|
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitElaboratedType(clang::ElaboratedType *et) {
|
|
|
|
//et->dump() ; std::cout << std::endl ;
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitPointerType(clang::PointerType *p) {
|
|
|
|
fdes->addArrayDim(-1) ;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitRecordType(clang::RecordType *rt) {
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitRecordType" << std::endl ;
|
|
|
|
rt->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
/* An array parameter may be a value within a record type. In this case we
|
|
|
|
may end up here multiple times for a field. The first
|
|
|
|
visitor is field type. Other visits are for the array parameters.
|
|
|
|
Return if we have already set the type for this field. */
|
|
|
|
if ( fdes->hasType() ) {
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
/* Test to see if we have an embedded anonymous struct/union. e.g. SB is anonymous below.
|
|
|
|
struct SA {
|
|
|
|
struct {
|
|
|
|
double d ;
|
|
|
|
} SB ;
|
|
|
|
} ;
|
|
|
|
*/
|
2015-03-24 16:01:31 +00:00
|
|
|
//std::cout << "hasNameForLinkage " << rt->getDecl()->hasNameForLinkage() << std::endl ;
|
|
|
|
if ( rt->getDecl()->hasNameForLinkage() ) {
|
|
|
|
if ( rt->getDecl()->getDeclName() ) {
|
|
|
|
//std::cout << "getDeclName " << rt->getDecl()->getDeclName().getAsString() << std::endl ;
|
|
|
|
fdes->setTypeName(rt->getDecl()->getQualifiedNameAsString()) ;
|
|
|
|
} else {
|
|
|
|
//std::cout << "getTypedefNameForAnonDecl " << rt->getDecl()->getTypedefNameForAnonDecl() << std::endl ;
|
|
|
|
fdes->setTypeName(rt->getDecl()->getTypedefNameForAnonDecl()->getQualifiedNameAsString()) ;
|
|
|
|
}
|
|
|
|
} else {
|
2015-02-26 15:02:31 +00:00
|
|
|
//rt->getDecl()->dump() ; std::cout << std::endl ;
|
|
|
|
// io_src code not possible for anonymous struct/unions. Set the I/O to 0 to ignore it.
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitRecordType found anonymous type, setIO = 0" << std::endl ;
|
|
|
|
}
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
fdes->setEnumString("TRICK_STRUCTURED") ;
|
|
|
|
fdes->setRecord(true) ;
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
In a template, this is the type that is defined by one of the incoming parameters.
|
|
|
|
template < class T > class A {
|
|
|
|
T var ;
|
|
|
|
} ;
|
|
|
|
In the above example this visitor is the resolved "T" class on the line "T var ;"
|
|
|
|
*/
|
|
|
|
bool FieldVisitor::VisitSubstTemplateTypeParmType(clang::SubstTemplateTypeParmType *sttpt) {
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitSubstTemplateTypeParmType" << std::endl ;
|
|
|
|
sttpt->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
if ( fdes->hasType() ) {
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitSubstTemplateTypeParmType field has type already" << std::endl ;
|
|
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
if ( sttpt->isBuiltinType() ) {
|
|
|
|
VisitBuiltinType((clang::BuiltinType *)sttpt->getAs<clang::BuiltinType>()) ;
|
|
|
|
} else if ( sttpt->isEnumeralType() ) {
|
|
|
|
VisitEnumType((clang::EnumType *)sttpt->getAs<clang::EnumType>()) ;
|
|
|
|
} else if ( sttpt->isRecordType() ) {
|
|
|
|
VisitRecordType((clang::RecordType *)sttpt->getAs<clang::RecordType>()) ;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::map < std::string , ClassValues * > processed_templates ;
|
|
|
|
/* This code handles handles class fields that define a new template type,
|
|
|
|
"my_var" in the below example.
|
|
|
|
|
|
|
|
template< class A>
|
|
|
|
class T {
|
|
|
|
A a ;
|
|
|
|
} ;
|
|
|
|
|
|
|
|
class B {
|
|
|
|
T<int> my_var ;
|
|
|
|
} ;
|
|
|
|
|
|
|
|
TODO: We need to save all of the parts of the template separately. There is code in
|
|
|
|
PrintFilecontents10 that I want to fix, but I would need the template info stored differently.
|
|
|
|
*/
|
|
|
|
bool FieldVisitor::VisitTemplateSpecializationType(clang::TemplateSpecializationType *tst) {
|
|
|
|
std::string tst_string = tst->desugar().getAsString() ;
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitTemplateSpecializationType " << tst_string << std::endl ;
|
|
|
|
tst->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! tst_string.compare( 0 , 9 , "class std") or ! tst_string.compare( 0 , 10 , "struct std") ) {
|
|
|
|
// This is a standard template library type. Set the io field to 0.
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
} else if ( ! tst_string.compare( 0 , 11 , "class Trick") or ! tst_string.compare( 0 , 12 , "struct Trick") ) {
|
|
|
|
// This is a Trick standard template library type. Set the io field to 0.
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
} else if ( fdes->getIO() != 0 ) {
|
|
|
|
// Continue processing only if we haven't set the IO spec to 0.
|
|
|
|
// This is a user template type. We'll need the expanded template class definition
|
|
|
|
clang::CXXRecordDecl *trec = tst->getAsCXXRecordDecl() ;
|
|
|
|
|
|
|
|
// If we cannot get a definition, ignore this parameter and return with no further processing.
|
|
|
|
if ( trec == NULL ) {
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
return false ;
|
|
|
|
}
|
|
|
|
|
|
|
|
clang::TagDecl * td = trec->getDefinition() ;
|
|
|
|
|
|
|
|
if ( td != NULL ) {
|
|
|
|
size_t pos ;
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitTemplateSpecializationType CXXRecordDecl " << std::endl ;
|
|
|
|
td->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
if ((pos = tst_string.find("class ")) != std::string::npos ) {
|
|
|
|
tst_string.erase(pos , 6) ;
|
|
|
|
}
|
|
|
|
// clang changes bool to _Bool. We need to change it back
|
|
|
|
if ((pos = tst_string.find("<_Bool")) != std::string::npos ) {
|
|
|
|
tst_string.replace(pos , 6, "<bool") ;
|
|
|
|
}
|
|
|
|
while ((pos = tst_string.find(" _Bool")) != std::string::npos ) {
|
|
|
|
tst_string.replace(pos , 6, " bool") ;
|
|
|
|
}
|
|
|
|
// NOTE: clang also changes FILE * to struct _SFILE *. We may need to change that too.
|
|
|
|
|
|
|
|
// Save container namespaces and classes.
|
|
|
|
fdes->getNamespacesAndClasses(td->getDeclContext()) ;
|
|
|
|
|
|
|
|
// Check to see if we've created a class that matches this template
|
|
|
|
if ( processed_templates.find(tst_string) == processed_templates.end() ) {
|
|
|
|
CXXRecordVisitor template_spec_cvis(ci , cs, hsd , pa, false, false, true) ;
|
|
|
|
processed_templates.insert(std::pair< std::string , ClassValues * >(tst_string , template_spec_cvis.get_class_data())) ;
|
|
|
|
|
|
|
|
// Use the current template type name, tst_string, as part of the mangled type name
|
|
|
|
// Some characters have to converted to underscores.
|
|
|
|
std::string mangled_name = tst_string ;
|
|
|
|
std::replace( mangled_name.begin(), mangled_name.end(), '<', '_') ;
|
|
|
|
std::replace( mangled_name.begin(), mangled_name.end(), '>', '_') ;
|
|
|
|
std::replace( mangled_name.begin(), mangled_name.end(), ' ', '_') ;
|
|
|
|
std::replace( mangled_name.begin(), mangled_name.end(), ',', '_') ;
|
|
|
|
std::replace( mangled_name.begin(), mangled_name.end(), ':', '_') ;
|
|
|
|
std::replace( mangled_name.begin(), mangled_name.end(), '*', '_') ;
|
|
|
|
|
|
|
|
|
|
|
|
template_spec_cvis.get_class_data()->setMangledTypeName(fdes->getContainerClass() + "_" +
|
|
|
|
fdes->getName() + "_" + mangled_name) ;
|
|
|
|
template_spec_cvis.TraverseCXXRecordDecl(clang::cast<clang::CXXRecordDecl>(td)) ;
|
|
|
|
fdes->setMangledTypeName(fdes->getContainerClass() + "_" + fdes->getName() + "_" + mangled_name) ;
|
|
|
|
template_spec_cvis.get_class_data()->setName(tst_string) ;
|
|
|
|
template_spec_cvis.get_class_data()->setFileName(fdes->getFileName()) ;
|
|
|
|
|
|
|
|
pa.printClass(template_spec_cvis.get_class_data()) ;
|
|
|
|
|
|
|
|
// template_spec_cvis is going to go out of scope. We need to make a copy of the ClassValues.
|
|
|
|
ClassValues * cval = new ClassValues(*(template_spec_cvis.get_class_data())) ;
|
|
|
|
processed_templates[tst_string] = cval ;
|
|
|
|
|
|
|
|
fdes->setEnumString("TRICK_STRUCTURED") ;
|
|
|
|
fdes->setRecord(true) ;
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "Added template class from FieldVisitor VisitTemplateSpecializationType " ;
|
|
|
|
std::cout << tst_string << std::endl ;
|
|
|
|
std::cout << *fdes << std::endl ;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
ClassValues * cval = processed_templates[tst_string] ;
|
|
|
|
fdes->setMangledTypeName(cval->getMangledTypeName()) ;
|
|
|
|
fdes->setEnumString("TRICK_STRUCTURED") ;
|
|
|
|
fdes->setRecord(true) ;
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitTemplateTypeParmType(clang::TemplateTypeParmType *ttp) {
|
|
|
|
fdes->setTypeName(ttp->getDecl()->getNameAsString()) ;
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
class IgnoreTypes {
|
|
|
|
public:
|
|
|
|
IgnoreTypes() {
|
|
|
|
types.insert("basic_ostringstream<char>") ;
|
|
|
|
}
|
|
|
|
std::set< std::string > types ;
|
|
|
|
} ;
|
|
|
|
IgnoreTypes ignore_types ;
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitTypedefType(clang::TypedefType *tt) {
|
|
|
|
size_t pos ;
|
|
|
|
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitTypedefType " << fdes->getName() << std::endl ;
|
|
|
|
tt->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return if we have set a typename
|
|
|
|
if ( fdes->hasType() ) {
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( tt->isEnumeralType() ) {
|
2016-01-29 15:27:41 +00:00
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << " FieldVisitor VisitTypedefType enumerated" << std::endl ;
|
|
|
|
}
|
2015-02-26 15:02:31 +00:00
|
|
|
fdes->setEnumString("TRICK_ENUMERATED") ;
|
|
|
|
fdes->setEnum(true) ;
|
|
|
|
std::string enum_type_name = tt->desugar().getAsString() ;
|
|
|
|
|
|
|
|
if ((pos = enum_type_name.find("enum ")) != std::string::npos ) {
|
|
|
|
enum_type_name.erase(pos , 5) ;
|
|
|
|
}
|
|
|
|
|
|
|
|
//std::cout << "enum name " << enum_type_name << std::endl ;
|
|
|
|
fdes->setTypeName(enum_type_name) ;
|
|
|
|
|
|
|
|
// Save container namespaces and classes.
|
|
|
|
const clang::TypedefNameDecl * tnd = tt->getDecl() ;
|
|
|
|
fdes->getNamespacesAndClasses(tnd->getDeclContext()) ;
|
|
|
|
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
} else if ( tt->isRecordType() ) {
|
|
|
|
std::string type_name = tt->desugar().getAsString() ;
|
2015-09-18 14:03:24 +00:00
|
|
|
if ((pos = type_name.find("class ")) != std::string::npos ) {
|
|
|
|
type_name.erase(pos , 6) ;
|
|
|
|
}
|
2015-02-26 15:02:31 +00:00
|
|
|
if ((pos = type_name.find("struct ")) != std::string::npos ) {
|
|
|
|
type_name.erase(pos , 7) ;
|
|
|
|
}
|
|
|
|
if ((pos = type_name.find("union ")) != std::string::npos ) {
|
|
|
|
type_name.erase(pos , 6) ;
|
|
|
|
}
|
|
|
|
// Typedefs of STL containers are ignored.
|
|
|
|
if ((pos = type_name.find("std::")) != std::string::npos ) {
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
return true ;
|
|
|
|
} else if (ignore_types.types.find(type_name) != ignore_types.types.end() ) {
|
|
|
|
// Ignore other system types that do not start with std::
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ( ! type_name.compare(0, 17, "basic_string<char") ) {
|
|
|
|
fdes->setEnumString("TRICK_STRING") ;
|
|
|
|
type_name = "std::string";
|
|
|
|
} else if ( ! type_name.compare("_IO_FILE") ) {
|
|
|
|
fdes->setEnumString("TRICK_FILE_PTR") ;
|
|
|
|
} else if ( ! type_name.compare("__sFILE") ) {
|
|
|
|
fdes->setEnumString("TRICK_FILE_PTR") ;
|
|
|
|
} else {
|
|
|
|
fdes->setEnumString("TRICK_STRUCTURED") ;
|
|
|
|
fdes->setRecord(true) ;
|
|
|
|
|
|
|
|
const clang::TypedefNameDecl * tnd = tt->getDecl() ;
|
|
|
|
fdes->getNamespacesAndClasses(tnd->getDeclContext()) ;
|
|
|
|
// If this typedef resolves to a class/template in std namespace, don't process it.
|
|
|
|
if ( fdes->namespace_begin() != fdes->namespace_end() ) {
|
|
|
|
std::string first_ns = *(fdes->namespace_begin()) ;
|
|
|
|
if ( ! first_ns.compare("std") ) {
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// test to see if the typedef name is a template type we have processed.
|
|
|
|
std::map < std::string , ClassValues * >::iterator mit ;
|
|
|
|
mit = processed_templates.find(type_name) ;
|
|
|
|
if ( mit != processed_templates.end() ) {
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "templated type has been processed before " << (*mit).second->getMangledTypeName() << std::endl ;
|
|
|
|
}
|
|
|
|
type_name = (*mit).second->getMangledTypeName() ;
|
|
|
|
} else {
|
|
|
|
// TODO: Is there a better way to determine if this is a template or not? Right now we're
|
|
|
|
// checking if the typename has a "<" character.
|
|
|
|
if ( type_name.find("<") != std::string::npos ) {
|
|
|
|
clang::CXXRecordDecl *trec = tt->getAsCXXRecordDecl() ;
|
|
|
|
unsigned int before_enum_size ;
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "templated type unprocessed! " << type_name << std::endl ;
|
|
|
|
trec->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
|
|
|
|
CXXRecordVisitor template_spec_cvis(ci , cs, hsd , pa, false, false, true) ;
|
|
|
|
template_spec_cvis.get_class_data()->setMangledTypeName(fdes->getName() + "_" +
|
|
|
|
clang::cast<clang::CXXRecordDecl>(trec)->getNameAsString()) ;
|
|
|
|
template_spec_cvis.TraverseCXXRecordDecl(trec) ;
|
|
|
|
fdes->setMangledTypeName(fdes->getName() + "_" + template_spec_cvis.get_class_data()->getName()) ;
|
|
|
|
template_spec_cvis.get_class_data()->setName(type_name) ;
|
|
|
|
template_spec_cvis.get_class_data()->setFileName(fdes->getFileName()) ;
|
|
|
|
|
|
|
|
ClassValues * cval = new ClassValues(*(template_spec_cvis.get_class_data())) ;
|
|
|
|
processed_templates.insert(std::pair< std::string , ClassValues * >(type_name , cval)) ;
|
|
|
|
pa.printClass(template_spec_cvis.get_class_data()) ;
|
|
|
|
|
|
|
|
fdes->setEnumString("TRICK_STRUCTURED") ;
|
|
|
|
fdes->setRecord(true) ;
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "Added template class from typedeffed field " << type_name << std::endl ;
|
|
|
|
std::cout << " fdes->getMangledTypeName " << fdes->getMangledTypeName() << std::endl ;
|
|
|
|
std::cout << *cval << std::endl ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
fdes->setTypeName(type_name) ;
|
|
|
|
fdes->setHasType(true) ;
|
|
|
|
} else if ( tt->isBuiltinType() ) {
|
2016-01-29 15:27:41 +00:00
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << " FieldVisitor VisitTypedefType builtintype" << std::endl ;
|
|
|
|
}
|
2015-02-26 15:02:31 +00:00
|
|
|
const clang::BuiltinType * bt = tt->getAs<clang::BuiltinType>() ;
|
|
|
|
VisitBuiltinType((clang::BuiltinType *)bt) ;
|
2016-01-29 15:27:41 +00:00
|
|
|
} else if ( tt->isArrayType() || tt->isPointerType()) {
|
|
|
|
clang::QualType qt = tt->desugar() ;
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "Typedef to constant array type" << std::endl ;
|
|
|
|
qt->dump() ;
|
|
|
|
}
|
|
|
|
// Calling visit type recursively with the typedeffed type
|
|
|
|
TraverseType(qt) ;
|
|
|
|
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "After TraverseType" << std::endl ;
|
|
|
|
std::cout << *fdes << std::endl ;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( debug_level >= 4 ) {
|
|
|
|
std::cout << "Typedef to something we don't handle yet" << std::endl ;
|
|
|
|
}
|
2015-02-26 15:02:31 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool FieldVisitor::VisitVarDecl( clang::VarDecl *v ) {
|
|
|
|
if ( debug_level >= 3 ) {
|
|
|
|
std::cout << "FieldVisitor VisitVarDecl " << fdes->getName() << std::endl ;
|
|
|
|
v->dump() ; std::cout << std::endl ;
|
|
|
|
}
|
|
|
|
fdes->setStatic(v->isStaticDataMember()) ;
|
|
|
|
/* If we have a static const integer type with an initializer value, this variable will
|
|
|
|
not be instantiated by the compiler. The compiler substitutes in the value internally.
|
|
|
|
set the IO to 0 to stop attribute printing */
|
|
|
|
// Note: gcc allows an initializer for floating point types too.
|
|
|
|
if ( v->isStaticDataMember() and
|
|
|
|
v->getType().isConstQualified() and
|
|
|
|
v->hasInit() ) {
|
|
|
|
fdes->setIO(0) ;
|
|
|
|
} else if ( v->isStaticDataMember() and
|
|
|
|
v->getType().isConstQualified() ) {
|
|
|
|
/* Static const members cannot be set through attributes code. Remove input
|
|
|
|
capabilities by taking current io specification & 1 */
|
|
|
|
fdes->setIO(fdes->getIO() & 1) ;
|
|
|
|
}
|
|
|
|
return true ;
|
|
|
|
}
|
|
|
|
|
|
|
|
FieldDescription * FieldVisitor::get_field_data() {
|
|
|
|
return fdes ;
|
|
|
|
}
|
|
|
|
|