2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
|
|
#include <iostream>
|
|
|
|
|
#include <sstream>
|
2016-04-13 21:01:59 +00:00
|
|
|
|
#include <stack>
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
|
#include "clang/AST/RecordLayout.h"
|
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
|
|
|
|
|
|
#include "ClassVisitor.hh"
|
|
|
|
|
#include "EnumVisitor.hh"
|
|
|
|
|
#include "EnumValues.hh"
|
|
|
|
|
#include "FieldVisitor.hh"
|
|
|
|
|
#include "Utilities.hh"
|
2016-04-08 13:26:57 +00:00
|
|
|
|
#include "CommentSaver.hh"
|
2015-02-26 15:02:31 +00:00
|
|
|
|
#include "PrintAttributes.hh"
|
2017-01-23 23:48:16 +00:00
|
|
|
|
#include "BraceMacro.hh"
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
|
|
extern llvm::cl::opt< int > debug_level ;
|
|
|
|
|
|
|
|
|
|
CXXRecordVisitor::CXXRecordVisitor(
|
|
|
|
|
clang::CompilerInstance & in_ci ,
|
|
|
|
|
CommentSaver & in_cs ,
|
|
|
|
|
HeaderSearchDirs & in_hsd ,
|
|
|
|
|
PrintAttributes & in_pa ,
|
2016-04-06 17:06:14 +00:00
|
|
|
|
bool in_include_virtual_base ) :
|
2015-02-26 15:02:31 +00:00
|
|
|
|
ci(in_ci) ,
|
|
|
|
|
cs(in_cs) ,
|
|
|
|
|
hsd(in_hsd) ,
|
|
|
|
|
pa(in_pa) ,
|
2016-04-11 13:01:54 +00:00
|
|
|
|
cval() ,
|
2016-04-06 17:06:14 +00:00
|
|
|
|
include_virtual_base(in_include_virtual_base) {}
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
|
|
CXXRecordVisitor::~CXXRecordVisitor() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CXXRecordVisitor::TraverseDecl(clang::Decl *d) {
|
|
|
|
|
if (!d)
|
|
|
|
|
return true;
|
|
|
|
|
if (d->isImplicit())
|
|
|
|
|
return true;
|
|
|
|
|
|
|
|
|
|
//std::cout << "CV " << d->getDeclKindName() << std::endl ;
|
|
|
|
|
|
|
|
|
|
switch ( d->getKind() ) {
|
|
|
|
|
case clang::Decl::ClassTemplateSpecialization : {
|
|
|
|
|
TraverseClassTemplateSpecializationDecl(static_cast<clang::ClassTemplateSpecializationDecl *>(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. We also only want to
|
|
|
|
|
process embedded classes that have public access. */
|
|
|
|
|
clang::RecordDecl * rd = crd->getDefinition() ;
|
2016-04-12 20:53:39 +00:00
|
|
|
|
if ( rd != NULL ) {
|
|
|
|
|
if ( rd->getAccess() == clang::AS_public ) {
|
2017-01-23 23:48:16 +00:00
|
|
|
|
if ( isInUserCode(ci , crd->RBRACELOC(), hsd) ) {
|
2016-04-12 20:53:39 +00:00
|
|
|
|
CXXRecordVisitor embedded_cvis(ci , cs, hsd , pa, true) ;
|
|
|
|
|
embedded_cvis.TraverseCXXRecordDecl(static_cast<clang::CXXRecordDecl *>(d)) ;
|
|
|
|
|
pa.printClass(embedded_cvis.get_class_data()) ;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// protected and private embedded classes cannot be used outside of their class
|
|
|
|
|
// in our auto-generated code. Keep a set of all classes of this type so we can
|
|
|
|
|
// test against them.
|
|
|
|
|
ClassValues temp_cv ;
|
|
|
|
|
temp_cv.getNamespacesAndClasses(crd->getDeclContext()) ;
|
|
|
|
|
private_embedded_classes.insert(temp_cv.getFullyQualifiedName() + crd->getNameAsString()) ;
|
|
|
|
|
//std::cout << "marking private " << temp_cv.getFullyQualifiedName() + crd->getNameAsString() << std::endl ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break ;
|
|
|
|
|
case clang::Decl::Enum : {
|
|
|
|
|
clang::EnumDecl * ed = static_cast<clang::EnumDecl *>(d) ;
|
|
|
|
|
/* This is an embedded enumeration within a class. Only process it if is public */
|
|
|
|
|
if ( ed->getAccess() == clang::AS_public ) {
|
|
|
|
|
EnumVisitor evis(ci, hsd) ;
|
|
|
|
|
evis.TraverseDecl(ed) ;
|
2016-04-11 13:01:54 +00:00
|
|
|
|
pa.printEnum(evis.get_enum_data()) ;
|
2016-04-15 19:10:37 +00:00
|
|
|
|
} else {
|
|
|
|
|
// protected and private embedded classes cannot be used outside of their class
|
|
|
|
|
// in our auto-generated code. Keep a set of all classes of this type so we can
|
|
|
|
|
// test against them.
|
|
|
|
|
ClassValues temp_cv ;
|
|
|
|
|
temp_cv.getNamespacesAndClasses(ed->getDeclContext()) ;
|
|
|
|
|
private_embedded_classes.insert(temp_cv.getFullyQualifiedName() + ed->getNameAsString()) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break ;
|
|
|
|
|
case clang::Decl::Field : {
|
2016-04-11 13:01:54 +00:00
|
|
|
|
FieldVisitor fvis(ci , hsd , cs, pa, cval.getName()) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
fvis.TraverseFieldDecl(static_cast<clang::FieldDecl *>(d)) ;
|
|
|
|
|
cval.addFieldDescription(fvis.get_field_data()) ;
|
|
|
|
|
}
|
|
|
|
|
break ;
|
|
|
|
|
case clang::Decl::Friend : {
|
|
|
|
|
TraverseFriendDecl(static_cast<clang::FriendDecl *>(d)) ;
|
|
|
|
|
}
|
|
|
|
|
break ;
|
|
|
|
|
case clang::Decl::Var : {
|
|
|
|
|
/* Static fields appear as vars. Treat it as a field. */
|
2016-04-11 13:01:54 +00:00
|
|
|
|
FieldVisitor fvis(ci , hsd , cs, pa, cval.getName()) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
fvis.TraverseVarDecl(static_cast<clang::VarDecl *>(d)) ;
|
|
|
|
|
cval.addFieldDescription(fvis.get_field_data()) ;
|
|
|
|
|
}
|
|
|
|
|
break ;
|
|
|
|
|
default :
|
|
|
|
|
break ;
|
|
|
|
|
}
|
|
|
|
|
return true ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CXXRecordVisitor::VisitDecl(clang::Decl *d) {
|
|
|
|
|
if ( debug_level >=2 ) {
|
2016-03-16 18:24:59 +00:00
|
|
|
|
std::cout << "\n\033[34mCXXRecordVisitor VisitDecl Decl = " << d->getDeclKindName() << "\033[0m" << std::endl ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
return true ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CXXRecordVisitor::VisitType(clang::Type *t) {
|
|
|
|
|
if ( debug_level >=2 ) {
|
|
|
|
|
std::cout << "\nCXXRecordVisitor Type = " << t->getTypeClassName() << std::endl ;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2015-09-18 18:18:05 +00:00
|
|
|
|
static bool isTypeTemplateSpecialization(const clang::Type * type_ptr) {
|
|
|
|
|
if ( type_ptr->getTypeClass() == clang::Type::TemplateSpecialization ) {
|
|
|
|
|
return true ;
|
|
|
|
|
} else if ( type_ptr->getTypeClass() == clang::Type::Elaborated ) {
|
|
|
|
|
const clang::ElaboratedType * et = type_ptr->getAs<clang::ElaboratedType>() ;
|
|
|
|
|
//std::cout << "\n[32minherited Type = " << et->getNamedType().getTypePtr()->getTypeClassName() << "[00m" << std::endl ;
|
|
|
|
|
return et->getNamedType().getTypePtr()->getTypeClass() == clang::Type::TemplateSpecialization ;
|
|
|
|
|
}
|
|
|
|
|
return false ;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
bool CXXRecordVisitor::VisitCXXRecordDecl( clang::CXXRecordDecl *rec ) {
|
|
|
|
|
if ( debug_level >= 2 ) {
|
|
|
|
|
rec->dump() ; std::cout << std::endl ;
|
|
|
|
|
}
|
2016-04-08 13:26:57 +00:00
|
|
|
|
|
|
|
|
|
// Return false to stop processing if there is no definition of this class
|
2015-02-26 15:02:31 +00:00
|
|
|
|
if ( rec->getDefinition() == NULL ) {
|
2016-04-08 13:26:57 +00:00
|
|
|
|
return false ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Return false to stop processing if this header file is excluded by one of many reasons.
|
2017-01-23 23:48:16 +00:00
|
|
|
|
std::string header_file_name = getFileName(ci , rec->RBRACELOC(), hsd) ;
|
2016-04-08 13:26:57 +00:00
|
|
|
|
char * rp = almostRealPath(header_file_name.c_str()) ;
|
2017-05-24 14:57:07 +00:00
|
|
|
|
if ( rp == NULL || pa.isHeaderExcluded(header_file_name, false) ) {
|
2017-03-15 20:53:56 +00:00
|
|
|
|
// mark the header as visited so PrintAttributes doesn't process it during addEmptyFiles()
|
|
|
|
|
pa.markHeaderAsVisited(header_file_name);
|
2016-04-08 13:26:57 +00:00
|
|
|
|
return false ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
2016-10-21 14:30:55 +00:00
|
|
|
|
cval.setCompat15(hsd.isPathInCompat15(rp)) ;
|
|
|
|
|
free(rp) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
2016-11-02 18:56:40 +00:00
|
|
|
|
// If we have trouble determining the containing namespace and classes skip this variable.
|
|
|
|
|
if ( !cval.getNamespacesAndClasses(rec->getDeclContext())) {
|
|
|
|
|
return false ;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
// If this class needs a default constructor, then the complier will generate one and we can call it.
|
|
|
|
|
if ( rec->needsImplicitDefaultConstructor() ) {
|
|
|
|
|
cval.setHasDefaultConstructor(true) ;
|
|
|
|
|
} else {
|
|
|
|
|
// Test all constructors to see if any of those are the default and public
|
|
|
|
|
clang::CXXRecordDecl::ctor_iterator cit ;
|
|
|
|
|
for ( cit = rec->ctor_begin() ; cit != rec->ctor_end() ; cit++ ) {
|
2021-02-06 01:32:36 +00:00
|
|
|
|
if ( ( !(*cit)->isDeleted() ) and (*cit)->isDefaultConstructor() and (*cit)->getAccess() == clang::AS_public ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
|
cval.setHasDefaultConstructor(true) ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Test to see there is no declared destructor or it is declared public
|
|
|
|
|
clang::CXXDestructorDecl * dd = rec->getDestructor() ;
|
|
|
|
|
if ( dd == NULL or dd->getAccess() == clang::AS_public ) {
|
|
|
|
|
cval.setHasPublicDestructor(true) ;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-08 13:26:57 +00:00
|
|
|
|
cval.setFileName(header_file_name) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
cval.setAbstract(rec->isAbstract()) ;
|
|
|
|
|
cval.setName(rec->getNameAsString()) ;
|
|
|
|
|
cval.setPOD(rec->isPOD()) ;
|
|
|
|
|
|
2016-10-21 14:30:55 +00:00
|
|
|
|
cval.setSize(rec->getASTContext().getASTRecordLayout(rec).getSize().getQuantity()) ;
|
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
|
|
//std::cout << "parsing " << cval.getName() << std::endl ;
|
|
|
|
|
//std::cout << " [34mprocessing inheritance " << rec->getNumBases() << " " << rec->getNumVBases() << "[00m" << std::endl ;
|
2016-11-02 18:56:40 +00:00
|
|
|
|
clang::CXXRecordDecl::base_class_iterator bcii ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
for ( bcii = rec->bases_begin() ; bcii != rec->bases_end() ; bcii++ ) {
|
|
|
|
|
if ( !bcii->isVirtual() ) {
|
|
|
|
|
const clang::Type * temp = bcii->getType().getTypePtr() ;
|
|
|
|
|
//std::cout << "\n[33minherited Type = " << temp->getTypeClassName() << "[00m" << std::endl ;
|
|
|
|
|
const clang::RecordType * rt = temp->getAs<clang::RecordType>() ;
|
|
|
|
|
if ( rt != NULL ) {
|
|
|
|
|
clang::RecordDecl * rd = rt->getDecl() ;
|
|
|
|
|
//std::cout << " [34m" << cval.getName() << " inherits from " << rd->getNameAsString() << "[00m" << std::endl ;
|
|
|
|
|
//rd->dump() ; std::cout << std::endl ;
|
2017-01-23 23:48:16 +00:00
|
|
|
|
if ( isInUserOrTrickCode(ci , rd->RBRACELOC(), hsd) ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
|
const clang::ASTRecordLayout &record_layout = rec->getASTContext().getASTRecordLayout(rec);
|
|
|
|
|
unsigned int inherit_class_offset ;
|
|
|
|
|
|
|
|
|
|
inherit_class_offset = record_layout.getBaseClassOffset(llvm::cast<clang::CXXRecordDecl>(rd)).getQuantity() ;
|
|
|
|
|
//std::cout << " [34minherit_class_offset = " << inherit_class_offset << "[00m" << std::endl ;
|
2017-01-23 23:48:16 +00:00
|
|
|
|
//std::cout << " [34m" << getFileName(ci , rd->RBRACELOC(), hsd) << "[00m" << std::endl ;
|
2016-04-11 13:01:54 +00:00
|
|
|
|
CXXRecordVisitor inherit_cvis(ci , cs, hsd , pa, false) ;
|
2017-05-24 14:57:07 +00:00
|
|
|
|
if (inherit_cvis.TraverseCXXRecordDecl(static_cast<clang::CXXRecordDecl *>(rd))) {
|
|
|
|
|
cval.addInheritedFieldDescriptions(inherit_cvis.get_class_data()->getFieldDescriptions(), inherit_class_offset, false) ;
|
|
|
|
|
// clear the field list in the inherited class so they are not freed when inherit_cvis
|
|
|
|
|
// goes out of scope.
|
|
|
|
|
inherit_cvis.get_class_data()->clearFieldDescription() ;
|
|
|
|
|
// If we are inheriting from a template specialization, don't save the inherited class. This list
|
|
|
|
|
// is maintained to call init_attr of the inherited classes. A template specialization does not
|
|
|
|
|
// havethese attributes.
|
|
|
|
|
if ( ! isTypeTemplateSpecialization(temp) ) {
|
|
|
|
|
// We want to save the inherited class data, but it's going to go out of scope so we need
|
|
|
|
|
// to make a copy of it.
|
|
|
|
|
ClassValues * icv = new ClassValues(*(inherit_cvis.get_class_data())) ;
|
|
|
|
|
// The inherited classes of this inherited class are not required in the copy,
|
|
|
|
|
// and they are going out of scope
|
|
|
|
|
cval.saveInheritAncestry(icv) ;
|
|
|
|
|
icv->clearInheritedClass() ;
|
|
|
|
|
|
|
|
|
|
// Save the copy of the inherited class to the current class
|
|
|
|
|
cval.addInheritedClass(inherit_cvis.get_class_data()->getFullyQualifiedTypeName()) ;
|
|
|
|
|
}
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//std::cout << " [34mend inheritance[00m" << std::endl ;
|
|
|
|
|
|
2016-04-11 13:01:54 +00:00
|
|
|
|
// Virtual base classes are parsed once
|
|
|
|
|
// When processing inherited classes include_virtual_base will be set to true
|
|
|
|
|
// so we don't process virtual inherited classes multiple times.
|
2015-02-26 15:02:31 +00:00
|
|
|
|
if ( include_virtual_base ) {
|
|
|
|
|
for ( bcii = rec->vbases_begin() ; bcii != rec->vbases_end() ; bcii++ ) {
|
|
|
|
|
const clang::Type * temp = bcii->getType().getTypePtr() ;
|
|
|
|
|
//std::cout << "\n[33minherited Type = " << temp->getTypeClassName() << "[00m" << std::endl ;
|
|
|
|
|
const clang::RecordType * rt = temp->getAs<clang::RecordType>() ;
|
|
|
|
|
if ( rt != NULL ) {
|
|
|
|
|
clang::RecordDecl * rd = rt->getDecl() ;
|
2016-04-11 13:01:54 +00:00
|
|
|
|
//std::cout << " [34m" << cval.getName() << " virtually inherits from "
|
|
|
|
|
// << rd->getNameAsString() << "[00m" << std::endl ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
//rd->dump() ; std::cout << std::endl ;
|
2017-01-23 23:48:16 +00:00
|
|
|
|
if ( isInUserOrTrickCode(ci , rd->RBRACELOC(), hsd) ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
|
const clang::ASTRecordLayout &record_layout = rec->getASTContext().getASTRecordLayout(rec);
|
|
|
|
|
unsigned int inherit_class_offset ;
|
|
|
|
|
|
|
|
|
|
// Virtual base classes have a fixed offset that cannot be accessed at runtime. We have clang's calculation
|
2016-04-11 13:01:54 +00:00
|
|
|
|
// to where the base class will be.
|
2015-02-26 15:02:31 +00:00
|
|
|
|
inherit_class_offset = record_layout.getVBaseClassOffset(llvm::cast<clang::CXXRecordDecl>(rd)).getQuantity() ;
|
|
|
|
|
|
|
|
|
|
//std::cout << " [34minherit_class_offset = " << inherit_class_offset << "[00m" << std::endl ;
|
2017-01-23 23:48:16 +00:00
|
|
|
|
//std::cout << " [34m" << getFileName(ci , rd->RBRACELOC(), hsd) << "[00m" << std::endl ;
|
2016-04-11 13:01:54 +00:00
|
|
|
|
CXXRecordVisitor inherit_cvis(ci , cs, hsd , pa, false) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
inherit_cvis.TraverseCXXRecordDecl(static_cast<clang::CXXRecordDecl *>(rd)) ;
|
2016-10-28 19:37:12 +00:00
|
|
|
|
cval.addInheritedFieldDescriptions(inherit_cvis.get_class_data()->getFieldDescriptions(), inherit_class_offset, true) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
// clear the field list in the inherited class so they are not freed when inherit_cvis goes out of scope.
|
|
|
|
|
inherit_cvis.get_class_data()->clearFieldDescription() ;
|
|
|
|
|
// If we are inheriting from a template specialization, don't save the inherited class. This list
|
|
|
|
|
// is maintained to call init_attr of the inherited classes. A template specialization does not have
|
|
|
|
|
// these attributes.
|
2015-09-18 18:18:05 +00:00
|
|
|
|
if ( ! isTypeTemplateSpecialization(temp) ) {
|
2015-02-26 15:02:31 +00:00
|
|
|
|
ClassValues * icv = new ClassValues(*(inherit_cvis.get_class_data())) ;
|
|
|
|
|
// The inherited classes of this inherted class are not required in the copy, and they are going out of scope
|
|
|
|
|
icv->clearInheritedClass() ;
|
|
|
|
|
|
|
|
|
|
// Save the copy of the inherited class to the current class
|
2016-04-11 13:01:54 +00:00
|
|
|
|
cval.addInheritedClass(inherit_cvis.get_class_data()->getFullyQualifiedTypeName()) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// clears obscured inherited variables caused by diamond inheritance
|
|
|
|
|
cval.clearAmbiguousVariables() ;
|
|
|
|
|
|
|
|
|
|
// sets the container class for all fields to the current class name
|
|
|
|
|
cval.setContainerClassForFields() ;
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-11 13:01:54 +00:00
|
|
|
|
// Test if we have a friend with the name "init_attr<class_name>"
|
2015-02-26 15:02:31 +00:00
|
|
|
|
bool CXXRecordVisitor::VisitFriendDecl( clang::FriendDecl *fd ) {
|
|
|
|
|
//std::cout << " [33mClassVisitor::VisitFriendDecl[00m" << std::endl ;
|
|
|
|
|
clang::TypeSourceInfo * tsi = fd->getFriendType() ;
|
|
|
|
|
if ( tsi == NULL ) {
|
|
|
|
|
clang::NamedDecl * nd = fd->getFriendDecl() ;
|
|
|
|
|
if ( nd != NULL and nd->getDeclName().isIdentifier()) {
|
|
|
|
|
//nd->dump() ;
|
|
|
|
|
std::string init_func = std::string("init_attr") ;
|
|
|
|
|
std::stringstream name_sp ;
|
2016-10-28 19:37:12 +00:00
|
|
|
|
cval.printNamespaces( name_sp , "__") ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
init_func += name_sp.str() + cval.getName() ;
|
|
|
|
|
std::string friend_str = nd->getName().str() ;
|
|
|
|
|
if ( ! friend_str.find(init_func) ) {
|
|
|
|
|
//std::cout << " [32mfound a friend![00m" << std::endl ;
|
|
|
|
|
cval.setHasInitAttrFriend(true) ;
|
2017-03-10 15:36:58 +00:00
|
|
|
|
} else if ( ! friend_str.find("init_attr") ) {
|
|
|
|
|
std::cerr << bold(color(WARNING,"Warning")) << " " << cval.getFileName() << ":" <<
|
|
|
|
|
ci.getSourceManager().getSpellingLineNumber(fd->getSourceRange().getBegin()) << ":" << std::endl ;
|
|
|
|
|
std::cerr << " friend " << friend_str << " does not match expected name " <<
|
|
|
|
|
init_func << std::endl ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ClassValues * CXXRecordVisitor::get_class_data() {
|
|
|
|
|
return &cval ;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 20:53:39 +00:00
|
|
|
|
std::set<std::string> CXXRecordVisitor::private_embedded_classes ;
|
|
|
|
|
|
2016-04-13 21:01:59 +00:00
|
|
|
|
void CXXRecordVisitor::addPrivateEmbeddedClass( std::string in_name ) {
|
|
|
|
|
private_embedded_classes.insert(in_name) ;
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-12 20:53:39 +00:00
|
|
|
|
bool CXXRecordVisitor::isPrivateEmbeddedClass( std::string in_name ) {
|
|
|
|
|
size_t pos ;
|
|
|
|
|
while ((pos = in_name.find("class ")) != std::string::npos ) {
|
|
|
|
|
in_name.erase(pos , 6) ;
|
|
|
|
|
}
|
|
|
|
|
while ((pos = in_name.find("struct ")) != std::string::npos ) {
|
|
|
|
|
in_name.erase(pos , 7) ;
|
|
|
|
|
}
|
2016-04-15 19:10:37 +00:00
|
|
|
|
while ((pos = in_name.find("enum ")) != std::string::npos ) {
|
|
|
|
|
in_name.erase(pos , 5) ;
|
|
|
|
|
}
|
2016-04-13 21:01:59 +00:00
|
|
|
|
while ((pos = in_name.find("const ")) != std::string::npos ) {
|
|
|
|
|
in_name.erase(pos , 6) ;
|
|
|
|
|
}
|
|
|
|
|
// remove any array or pointer dimensions.
|
|
|
|
|
if ( in_name.find_first_of("[*") != std::string::npos ) {
|
|
|
|
|
in_name.erase(in_name.find_first_of("[*")) ;
|
|
|
|
|
}
|
|
|
|
|
// remove trailing spaces
|
2019-09-23 19:25:27 +00:00
|
|
|
|
in_name.erase(std::find_if(in_name.rbegin(), in_name.rend(),
|
|
|
|
|
[](int c) {return !std::isspace(c);}).base(), in_name.end());
|
2016-04-13 21:01:59 +00:00
|
|
|
|
|
|
|
|
|
// remove all template arguments "<text>"
|
|
|
|
|
bool template_arg_found ;
|
|
|
|
|
do {
|
|
|
|
|
template_arg_found = false ;
|
|
|
|
|
std::stack<int> bracket_pos ;
|
|
|
|
|
for ( int ii = 0 ; ii < in_name.length() ; ii++ ) {
|
|
|
|
|
if ( in_name[ii] == '<' ) {
|
|
|
|
|
bracket_pos.push(ii) ;
|
|
|
|
|
} else if ( in_name[ii] == '>' ) {
|
|
|
|
|
int begin = bracket_pos.top() ;
|
|
|
|
|
bracket_pos.pop() ;
|
|
|
|
|
if ( bracket_pos.empty() ) {
|
|
|
|
|
template_arg_found = true ;
|
|
|
|
|
in_name.erase(begin, ii - begin + 1) ;
|
|
|
|
|
break ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} while ( template_arg_found == true ) ;
|
2016-04-12 20:53:39 +00:00
|
|
|
|
|
|
|
|
|
std::set<std::string>::iterator it ;
|
|
|
|
|
it = private_embedded_classes.find(in_name) ;
|
|
|
|
|
if ( it != private_embedded_classes.end() ) {
|
|
|
|
|
return true ;
|
|
|
|
|
}
|
|
|
|
|
return false ;
|
|
|
|
|
}
|