提交 261edfd7 编写于 作者: M Matias Romeo

Add vector support to ABI generator

上级 844586a7
......@@ -27,18 +27,29 @@ void abi_generator::set_compiler_instance(CompilerInstance& compiler_instance) {
}
void abi_generator::handle_tagdecl_definition(TagDecl* tag_decl) {
ASTContext& ctx = tag_decl->getASTContext();
auto decl_location = tag_decl->getLocation().printToString(ctx.getSourceManager());
ast_context = &tag_decl->getASTContext();
auto decl_location = tag_decl->getLocation().printToString(ast_context->getSourceManager());
try {
handle_decl(tag_decl);
} FC_CAPTURE_AND_RETHROW((decl_location)) }
string abi_generator::remove_namespace(const string& full_name) {
string type_name = full_name;
auto pos = type_name.find_last_of("::");
if(pos != string::npos)
type_name = type_name.substr(pos+1);
return type_name;
int i = full_name.size();
int on_spec = 0;
int colons = 0;
while( --i >= 0 ) {
if( full_name[i] == '>' ) {
++on_spec; colons=0;
} else if( full_name[i] == '<' ) {
--on_spec; colons=0;
} else if( full_name[i] == ':' && !on_spec) {
if (++colons == 2)
return full_name.substr(i+2);
} else {
colons = 0;
}
}
return full_name;
}
bool abi_generator::is_builtin_type(const string& type_name) {
......@@ -70,13 +81,14 @@ void abi_generator::handle_decl(const Decl* decl) { try {
ABI_ASSERT(decl != nullptr);
ABI_ASSERT(output != nullptr);
ABI_ASSERT(ast_context != nullptr);
ASTContext& ctx = decl->getASTContext();
const RawComment* raw_comment = ctx.getRawCommentForDeclNoCache(decl);
//ASTContext& ctx = decl->getASTContext();
const RawComment* raw_comment = ast_context->getRawCommentForDeclNoCache(decl);
if(!raw_comment) return;
SourceManager& source_manager = ctx.getSourceManager();
SourceManager& source_manager = ast_context->getSourceManager();
auto file_name = source_manager.getFilename(raw_comment->getLocStart());
if ( !abi_context.empty() && !file_name.startswith(abi_context) ) {
return;
......@@ -105,7 +117,7 @@ void abi_generator::handle_decl(const Decl* decl) { try {
auto qt = action_decl->getTypeForDecl()->getCanonicalTypeInternal();
auto type_name = remove_namespace(add_struct(qt));
auto type_name = add_struct(qt);
ABI_ASSERT(!is_builtin_type(type_name),
"A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name));
......@@ -128,7 +140,7 @@ void abi_generator::handle_decl(const Decl* decl) { try {
ABI_ASSERT(table_decl != nullptr);
auto qt = table_decl->getTypeForDecl()->getCanonicalTypeInternal();
auto type_name = remove_namespace(add_struct(qt));
auto type_name = add_struct(qt);
ABI_ASSERT(!is_builtin_type(type_name),
"A built-in type with the same name exists, try using another name: ${type_name}", ("type_name",type_name));
......@@ -140,16 +152,16 @@ void abi_generator::handle_decl(const Decl* decl) { try {
table.name = boost::algorithm::to_lower_copy(boost::erase_all_copy(type_name, "_"));
table.type = type_name;
if(params.size() >= 1)
table.index_type = params[0];
if(params.size() >= 1) {
table.name = params[0];
}
if(params.size() >= 2)
table.index_type = params[1];
else { try {
guess_index_type(table, *s);
} FC_CAPTURE_AND_RETHROW( (type_name) ) }
if(params.size() >= 2) {
table.name = params[1];
}
try {
guess_key_names(table, *s);
} FC_CAPTURE_AND_RETHROW( (type_name) )
......@@ -181,9 +193,11 @@ bool abi_generator::is_string(const string& type) {
void abi_generator::get_all_fields(const struct_def& s, vector<field_def>& fields) {
abi_serializer abis(*output);
for(const auto& field : s.fields) {
fields.push_back(field);
}
if(s.base.size()) {
const auto* base = find_struct(s.base);
ABI_ASSERT(base, "Unable to find base type ${type}",("type",s.base));
......@@ -211,7 +225,7 @@ void abi_generator::guess_index_type(table_def& table, const struct_def s) {
vector<field_def> fields;
get_all_fields(s, fields);
if( is_str_index(fields) ) {
table.index_type = "str";
} else if ( is_i64i64i64_index(fields) ) {
......@@ -230,15 +244,28 @@ void abi_generator::guess_key_names(table_def& table, const struct_def s) {
vector<field_def> fields;
get_all_fields(s, fields);
if( table.index_type == "i64i64i64" && is_i64i64i64_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name, fields[1].name, fields[2].name};
table.key_types = vector<type_name>{fields[0].type, fields[1].type, fields[2].type};
} else if( table.index_type == "i128i128" && is_i128i128_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name, fields[1].name};
table.key_types = vector<type_name>{fields[0].type, fields[1].type};
} else if( table.index_type == "i64" && is_i64_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name};
table.key_types = vector<type_name>{fields[0].type};
if( table.index_type == "i64i64i64" || table.index_type == "i128i128"
|| table.index_type == "i64") {
table.key_names.clear();
table.key_types.clear();
unsigned int key_size = 0;
bool valid_key = false;
for(auto& f : fields) {
table.key_names.emplace_back(f.name);
table.key_types.emplace_back(f.type);
key_size += type_size[f.type]/8;
if((table.index_type == "i64i64i64" && key_size >= sizeof(uint64_t)*3) ||
(table.index_type == "i64" && key_size >= sizeof(uint64_t)) ||
(table.index_type == "i128i128" && key_size >= sizeof(__int128)*2)) {
valid_key = true;
break;
}
}
ABI_ASSERT(valid_key, "Unable to guess key names");
} else if( table.index_type == "str" && is_str_index(fields) ) {
table.key_names = vector<field_name>{fields[0].name};
table.key_types = vector<type_name>{fields[0].type};
......@@ -298,95 +325,196 @@ bool abi_generator::is_one_filed_no_base(const string& type_name) {
}
string abi_generator::decl_to_string(clang::Decl* d) {
ASTContext& ctx = d->getASTContext();
const auto& sm = ctx.getSourceManager();
//ASTContext& ctx = d->getASTContext();
const auto& sm = ast_context->getSourceManager();
clang::SourceLocation b(d->getLocStart()), _e(d->getLocEnd());
clang::SourceLocation e(clang::Lexer::getLocForEndOfToken(_e, 0, sm, compiler_instance->getLangOpts()));
return string(sm.getCharacterData(b),
sm.getCharacterData(e)-sm.getCharacterData(b));
}
void abi_generator::add_typedef(const clang::TypedefType* typeDef) {
bool abi_generator::is_typedef(const clang::QualType& qt) {
return isa<TypedefType>(qt.getTypePtr());
}
vector<type_def> types_to_add;
while(typeDef != nullptr) {
const auto* typedef_decl = typeDef->getDecl();
auto qt = typedef_decl->getUnderlyingType().getUnqualifiedType();
bool abi_generator::is_elaborated(const clang::QualType& qt) {
return isa<ElaboratedType>(qt.getTypePtr());
}
auto full_name = translate_type(qt.getAsString(compiler_instance->getLangOpts()));
bool abi_generator::is_vector(const clang::QualType& vqt) {
QualType qt(vqt);
//HACK: We need to think another way to stop importing the "typedef chain"
if( full_name.find("<") != string::npos ) {
break;
}
if ( is_elaborated(qt) )
qt = qt->getAs<clang::ElaboratedType>()->getNamedType();
auto new_type_name = translate_type(typedef_decl->getName().str());
if(is_builtin_type(new_type_name)) {
break;
}
return isa<clang::TemplateSpecializationType>(qt.getTypePtr()) \
&& boost::starts_with( get_type_name(qt, false), "vector");
}
bool abi_generator::is_vector(const string& type_name) {
return boost::ends_with(type_name, "[]");
}
//TODO: ABI_ASSERT TypeName length for typedef
type_def abi_typedef;
abi_typedef.new_type_name = new_type_name;
abi_typedef.type = remove_namespace( full_name );
bool abi_generator::is_struct_specialization(const clang::QualType& qt) {
return is_struct(qt) && isa<clang::TemplateSpecializationType>(qt.getTypePtr());
}
const auto* td = find_type(abi_typedef.new_type_name);
if( td ) {
ABI_ASSERT(abi_typedef.type == td->type);
typeDef = qt->getAs<clang::TypedefType>();
continue;
}
bool abi_generator::is_struct(const clang::QualType& sqt) {
clang::QualType qt(sqt);
const auto* type = qt.getTypePtr();
return !is_vector(qt) && (type->isStructureType() || type->isClassType());
}
clang::QualType abi_generator::get_vector_element_type(const clang::QualType& qt) {
const auto* tst = clang::dyn_cast<const clang::TemplateSpecializationType>(qt.getTypePtr());
ABI_ASSERT(tst != nullptr);
const clang::TemplateArgument& arg0 = tst->getArg(0);
return arg0.getAsType();
}
string abi_generator::get_vector_element_type(const string& type_name) {
if( is_vector(type_name) )
return type_name.substr(0, type_name.size()-2);
return type_name;
}
string abi_generator::get_type_name(const clang::QualType& qt, bool with_namespace=false) {
auto name = clang::TypeName::getFullyQualifiedName(qt, *ast_context);
if(!with_namespace)
name = remove_namespace(name);
return name;
}
clang::QualType abi_generator::add_typedef(const clang::QualType& tqt) {
//ilog("addTypeDef => ${a} ${b} [${c}]", ("a",abi_typedef.new_type_name)("b",abi_typedef.type)("c",getFullScope(qt)));
ABI_ASSERT(abi_typedef.new_type_name != abi_typedef.type,
"Unable to export typedef `${td}` at ${at}",
("td",decl_to_string(typeDef->getDecl()))
("at",typeDef->getDecl()->getLocation().printToString(typeDef->getDecl()->getASTContext().getSourceManager()))
);
clang::QualType qt(get_named_type_if_elaborated(tqt));
types_to_add.push_back(abi_typedef);
typeDef = qt->getAs<clang::TypedefType>();
const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
auto underlying_type = td_decl->getUnderlyingType().getUnqualifiedType();
auto new_type_name = td_decl->getName().str();
auto underlying_type_name = get_type_name(underlying_type);
if ( is_vector(underlying_type) ) {
underlying_type_name = add_vector(underlying_type);
}
type_def abi_typedef;
abi_typedef.new_type_name = new_type_name;
abi_typedef.type = translate_type(underlying_type_name);
const auto* td = find_type(abi_typedef.new_type_name);
if(!td && !is_struct_specialization(underlying_type) ) {
output->types.push_back(abi_typedef);
} else {
if(td) ABI_ASSERT(abi_typedef.type == td->type);
}
std::reverse(types_to_add.begin(), types_to_add.end());
output->types.insert(output->types.end(), types_to_add.begin(), types_to_add.end());
if( is_typedef(underlying_type) && !is_builtin_type(get_type_name(underlying_type)) )
return add_typedef(underlying_type);
return underlying_type;
}
string abi_generator::get_name_to_add(const clang::QualType& qual_type) {
clang::CXXRecordDecl::base_class_range abi_generator::get_struct_bases(const clang::QualType& sqt) {
auto type_name = qual_type.getAsString(compiler_instance->getLangOpts());
const auto* typedef_type = qual_type->getAs<clang::TypedefType>();
if( !is_builtin_type(type_name) && typedef_type != nullptr) {
add_typedef(typedef_type);
}
clang::QualType qt(sqt);
if(is_typedef(qt)) {
const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
qt = td_decl->getUnderlyingType().getUnqualifiedType();
}
const auto* record_type = qt->getAs<clang::RecordType>();
ABI_ASSERT(record_type != nullptr);
auto cxxrecord_decl = clang::dyn_cast<CXXRecordDecl>(record_type->getDecl());
ABI_ASSERT(cxxrecord_decl != nullptr);
//record_type->getCanonicalTypeInternal().dump();
return type_name;
auto bases = cxxrecord_decl->bases();
return bases;
}
string abi_generator::add_struct(const clang::QualType& qual_type) {
const clang::RecordDecl::field_range abi_generator::get_struct_fields(const clang::QualType& sqt) {
clang::QualType qt(sqt);
ABI_ASSERT(output != nullptr);
if(is_typedef(qt)) {
const auto* td_decl = qt->getAs<clang::TypedefType>()->getDecl();
qt = td_decl->getUnderlyingType().getUnqualifiedType();
}
const auto* record_type = qual_type->getAs<clang::RecordType>();
const auto* record_type = qt->getAs<clang::RecordType>();
ABI_ASSERT(record_type != nullptr);
return record_type->getDecl()->fields();
}
string abi_generator::add_vector(const clang::QualType& vqt) {
clang::QualType qt(get_named_type_if_elaborated(vqt));
auto vector_element_type = get_vector_element_type(qt);
ABI_ASSERT(!is_vector(vector_element_type), "Only one-dimensional arrays are supported");
const auto* record_decl = clang::cast_or_null<clang::CXXRecordDecl>(record_type->getDecl()->getDefinition());
ABI_ASSERT(record_decl != nullptr);
add_type(vector_element_type);
auto vector_element_type_str = translate_type(get_type_name(vector_element_type));
vector_element_type_str += "[]";
ASTContext& ctx = record_decl->getASTContext();
return vector_element_type_str;
}
auto full_name = get_name_to_add(qual_type);
string abi_generator::add_type(const clang::QualType& tqt) {
auto name = remove_namespace(full_name);
clang::QualType qt(get_named_type_if_elaborated(tqt));
//Only export user defined types
if( is_builtin_type(name) ) {
return name;
string full_type_name = translate_type(get_type_name(qt, true));
string type_name = translate_type(get_type_name(qt));
bool is_type_def = false;
if( is_builtin_type(type_name) ) {
return type_name;
}
if( is_typedef(qt) ) {
qt = add_typedef(qt);
if( is_builtin_type(translate_type(get_type_name(qt))) ) {
return type_name;
}
is_type_def = true;
}
if( is_vector(qt) ) {
auto vector_type_name = add_vector(qt);
return is_type_def ? type_name : vector_type_name;
}
if( is_struct(qt) ) {
return add_struct(qt, full_type_name);
}
ABI_ASSERT(false, "types can only be: vector, struct, class or a built-in type. (${type}) ", ("type",get_type_name(qt)));
return type_name;
}
clang::QualType abi_generator::get_named_type_if_elaborated(const clang::QualType& qt) {
if( is_elaborated(qt) ) {
return qt->getAs<clang::ElaboratedType>()->getNamedType();
}
return qt;
}
const auto* type = qual_type.getTypePtr();
string abi_generator::add_struct(const clang::QualType& sqt, string full_name) {
clang::QualType qt(get_named_type_if_elaborated(sqt));
if( full_name.empty() ) {
full_name = get_type_name(qt, true);
}
ABI_ASSERT(type->isStructureType() || type->isClassType(), "Only struct and class are supported. ${full_name}",("full_name",full_name));
auto name = remove_namespace(full_name);
ABI_ASSERT(is_struct(qt), "Only struct and class are supported. ${full_name}",("full_name",full_name));
ABI_ASSERT(name.size() <= sizeof(type_name),
"Type name > ${maxsize}, ${name}",
......@@ -400,58 +528,52 @@ string abi_generator::add_struct(const clang::QualType& qual_type) {
return name;
}
auto bases = record_decl->bases();
auto total_bases = distance(bases.begin(), bases.end());
if( total_bases > 1 ) {
ABI_ASSERT(false, "Multiple inheritance not supported - ${type}", ("type",full_name));
}
auto bases = get_struct_bases(qt);
auto bitr = bases.begin();
int total_bases = 0;
string base_name;
if( total_bases == 1 ) {
auto qt = bases.begin()->getType();
base_name = add_struct(qt);
while( bitr != bases.end() ) {
auto base_qt = bitr->getType();
const auto* record_type = base_qt->getAs<clang::RecordType>();
if( record_type && is_struct(base_qt) && !record_type->getDecl()->field_empty() ) {
ABI_ASSERT(total_bases == 0, "Multiple inheritance not supported - ${type}", ("type",full_name));
base_name = add_type(base_qt);
++total_bases;
}
++bitr;
}
struct_def abi_struct;
for (const auto& field : record_decl->fields()) {
field_def struct_field;
for (const clang::FieldDecl* field : get_struct_fields(qt) ) {
clang::QualType qt = field->getType();
string field_name = field->getNameAsString();
string field_type_name = add_type(qt);
auto field_type = translate_type(remove_namespace(get_name_to_add(qt.getUnqualifiedType())));
ABI_ASSERT(field_type.size() <= sizeof(decltype(struct_field.type)),
"Type name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field_type)("maxsize",sizeof(decltype(struct_field.type))));
field_def struct_field{field_name, field_type_name};
ABI_ASSERT(is_builtin_type(get_vector_element_type(struct_field.type))
|| find_struct(get_vector_element_type(struct_field.type))
|| find_type(get_vector_element_type(struct_field.type))
, "Unknown type ${type} [${abi}]",("type",struct_field.type)("abi",*output));
ABI_ASSERT(field->getNameAsString().size() <= sizeof(decltype(struct_field.name)) ,
"Field name > ${maxsize}, ${type}::${name}", ("type",full_name)("name",field->getNameAsString())("maxsize", sizeof(decltype(struct_field.name))));
if( qt->getAs<clang::RecordType>() ) {
add_struct(qt);
//TODO: simplify if OPT_SINGLE_FIELD_STRUCT is enabled
}
struct_field.name = field->getNameAsString();
struct_field.type = field_type;
ABI_ASSERT(struct_field.type.size() <= sizeof(decltype(struct_field.type)),
"Type name > ${maxsize}, ${type}::${name}", ("type",struct_field.type)("name",struct_field.name)("maxsize",sizeof(decltype(struct_field.type))));
ABI_ASSERT(is_builtin_type(struct_field.type) || find_struct(struct_field.type), "Unknown type ${type} ${name} ${ttt} ${sss}", ("type",struct_field.type)("name",struct_field.name)("types", output->types)("structs",output->structs));
ABI_ASSERT(field->getNameAsString().size() <= sizeof(decltype(struct_field.name)) ,
"Field name > ${maxsize}, ${type}::${name}", ("type",struct_field.type)("name",struct_field.name)("maxsize",sizeof(decltype(struct_field.type))));
type_size[string(struct_field.type)] = ctx.getTypeSize(qt);
type_size[string(struct_field.type)] = is_vector(struct_field.type) ? 0 : ast_context->getTypeSize(qt);
abi_struct.fields.push_back(struct_field);
}
abi_struct.name = resolve_type(name);
abi_struct.base = remove_namespace(base_name);
output->structs.push_back(abi_struct);
if(verbose) {
cerr << "Adding type " << resolve_type(name) << " (" << full_name << ")\n";
}
abi_struct.base = base_name;
output->structs.push_back(abi_struct);
full_types[name] = full_name;
return full_name;
return name;
}
}
\ No newline at end of file
......@@ -19,6 +19,7 @@
#include "clang/Lex/Preprocessor.h"
#include "clang/Tooling/Tooling.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Core/QualTypeNames.h"
#include "llvm/Support/raw_ostream.h"
#include <boost/algorithm/string.hpp>
......@@ -60,7 +61,7 @@ namespace eosio {
map<string, uint64_t> type_size;
map<string, string> full_types;
string abi_context;
clang::ASTContext* ast_context;
public:
enum optimization {
......@@ -70,7 +71,8 @@ namespace eosio {
abi_generator()
:optimizations(0)
, output(nullptr)
, compiler_instance(nullptr)
, compiler_instance(nullptr)
, ast_context(nullptr)
{}
~abi_generator() {}
......@@ -161,11 +163,29 @@ namespace eosio {
string decl_to_string(clang::Decl* d);
void add_typedef(const clang::TypedefType* typeDef);
bool is_typedef(const clang::QualType& qt);
QualType add_typedef(const clang::QualType& qt);
bool is_vector(const clang::QualType& qt);
bool is_vector(const string& type_name);
string add_vector(const clang::QualType& qt);
bool is_struct(const clang::QualType& qt);
string add_struct(const clang::QualType& qt, string full_type_name="");
string get_type_name(const clang::QualType& qt, bool no_namespace);
string add_type(const clang::QualType& tqt);
bool is_elaborated(const clang::QualType& qt);
bool is_struct_specialization(const clang::QualType& qt);
string get_name_to_add(const clang::QualType& qual_type);
QualType get_vector_element_type(const clang::QualType& qt);
string get_vector_element_type(const string& type_name);
clang::QualType get_named_type_if_elaborated(const clang::QualType& qt);
string add_struct(const clang::QualType& qual_type);
const clang::RecordDecl::field_range get_struct_fields(const clang::QualType& qt);
clang::CXXRecordDecl::base_class_range get_struct_bases(const clang::QualType& qt);
};
struct abi_generator_astconsumer : public ASTConsumer {
......
......@@ -42,16 +42,14 @@ static cl::opt<bool> abi_opt_sfs(
cl::desc("Optimize single field struct"),
cl::cat(abi_generator_category));
int main(int argc, const char **argv) { try {
int main(int argc, const char **argv) { abi_def output; try {
CommonOptionsParser op(argc, argv, abi_generator_category);
ClangTool Tool(op.getCompilations(), op.getSourcePathList());
abi_def abi;
int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, abi).get());
int result = Tool.run(create_factory(abi_verbose, abi_opt_sfs, abi_context, output).get());
if(!result) {
abi_serializer(abi).validate();
fc::json::save_to_file<abi_def>(abi, abi_destination, true);
abi_serializer(output).validate();
fc::json::save_to_file<abi_def>(output, abi_destination, true);
}
return result;
} FC_CAPTURE_AND_LOG(()); return -1; }
} FC_CAPTURE_AND_LOG((output)); return -1; }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册