Clean up type printer

This commit is contained in:
Fangrui Song 2017-12-29 12:58:11 -08:00
parent daaf3a701b
commit 43ea2fcc53

View File

@ -2,35 +2,22 @@
#include <string>
#include "loguru.hpp"
#if USE_CLANG_CXX
# include "CXTranslationUnit.h"
# include "clang/AST/Type.h"
# include "clang/AST/PrettyPrinter.h"
# include "clang/Frontend/ASTUnit.h"
# include "llvm/ADT/SmallString.h"
# include "llvm/Support/raw_ostream.h"
using namespace clang;
// Extracted from clang/tools/libclang/CXType.cpp
static inline QualType GetQualType(CXType CT) {
return QualType::getFromOpaquePtr(CT.data[0]);
}
static inline CXTranslationUnit GetTU(CXType CT) {
return static_cast<CXTranslationUnit>(CT.data[1]);
}
#endif
namespace {
void AddName(std::string& before, const std::string& name) {
if (before.size() &&
(before.back() != ' ' && before.back() != '*' && before.back() != '&'))
before.push_back(' ');
before.append(name);
}
int GetNameInsertingPosition(const std::string& type_desc,
const std::string& return_type) {
// Check if type_desc contains an (.
if (type_desc.empty() || type_desc.size() <= return_type.size() ||
if (type_desc.size() <= return_type.size() ||
type_desc.find("(", 0) == std::string::npos)
return -1;
// Find a first character where the return_type differs from the
return type_desc.size();
// Find the first character where the return_type differs from the
// function_type. In most cases this is the place where the function name
// should be inserted.
int ret = 0;
@ -46,7 +33,7 @@ int GetNameInsertingPosition(const std::string& type_desc,
} else {
// Otherwise return type is just a prefix of the function_type.
// Skip any eventual spaces after the return type.
while (ret < int(type_desc.size()) && type_desc[ret] == ' ')
while (type_desc[ret] == ' ')
ret++;
}
return ret;
@ -71,99 +58,56 @@ std::string GetFunctionSignature(IndexFile* db,
num_args++;
}
std::string type_desc;
int function_name_offset;
#if USE_CLANG_CXX
{
CXType CT = clang_getCursorType(decl->cursor);
QualType T = GetQualType(CT);
if (!T.isNull()) {
CXTranslationUnit TU = GetTU(CT);
SmallString<64> Str;
llvm::raw_svector_ostream OS(Str);
PrintingPolicy PP(cxtu::getASTUnit(TU)->getASTContext().getLangOpts());
std::string type_desc = ClangCursor(decl->cursor).get_type_description();
int function_name_offset = GetNameInsertingPosition(
type_desc, ::ToString(clang_getTypeSpelling(
clang_getCursorResultType(decl->cursor))));
T.print(OS, PP, "=^_^=");
type_desc = OS.str();
function_name_offset = type_desc.find("=^_^=");
if (type_desc[function_name_offset + 5] != ')')
type_desc = type_desc.replace(function_name_offset, 5, "");
else {
type_desc = type_desc.replace(function_name_offset, 6, "");
for (int i = function_name_offset; i-- > 0; )
if (type_desc[i] == '(') {
type_desc.erase(type_desc.begin() + i);
break;
}
function_name_offset--;
}
}
}
#else
type_desc = ClangCursor(decl->cursor).get_type_description();
std::string return_type = ::ToString(
clang_getTypeSpelling(clang_getCursorResultType(decl->cursor)));
function_name_offset = GetNameInsertingPosition(type_desc, return_type);
#endif
if (function_name_offset >= 0 && type_desc[function_name_offset] == '(') {
if (num_args > 0) {
// Find positions to insert argument names.
// Last argument name is before ')'
num_args = 0;
// Other argument names come before ','
for (int balance = 0, i = function_name_offset;
i < int(type_desc.size()) && num_args < int(args.size()); i++) {
if (type_desc[i] == '(' || type_desc[i] == '[')
balance++;
else if (type_desc[i] == ')' || type_desc[i] == ']') {
if (--balance <= 0) {
args[num_args].first = i;
break;
}
} else if (type_desc[i] == ',' && balance == 1)
args[num_args++].first = i;
}
// Second pass: Insert argument names before each comma.
int i = 0;
std::string type_desc_with_names;
for (auto& arg : args) {
if (arg.first < 0) {
LOG_S(ERROR)
<< "When adding argument names to '" << type_desc
<< "', failed to detect positions to insert argument names";
if (type_desc[function_name_offset] == '(') {
// Find positions to insert argument names.
// Argument name are before ',' or closing ')'.
num_args = 0;
for (int balance = 0, i = function_name_offset;
i < int(type_desc.size()) && num_args < int(args.size()); i++) {
if (type_desc[i] == '(' || type_desc[i] == '[')
balance++;
else if (type_desc[i] == ')' || type_desc[i] == ']') {
if (--balance <= 0) {
args[num_args].first = i;
break;
}
if (arg.second.empty())
continue;
// TODO Use inside-out syntax. Note, clang/lib/AST/TypePrinter.cpp does
// not print arg names.
type_desc_with_names.insert(type_desc_with_names.end(), &type_desc[i],
&type_desc[arg.first]);
i = arg.first;
if (type_desc_with_names.size() &&
(type_desc_with_names.back() != ' ' &&
type_desc_with_names.back() != '*' &&
type_desc_with_names.back() != '&'))
type_desc_with_names.push_back(' ');
type_desc_with_names.append(arg.second);
}
type_desc_with_names.insert(type_desc_with_names.end(),
type_desc.begin() + i, type_desc.end());
type_desc = std::move(type_desc_with_names);
} else if (type_desc[i] == ',' && balance == 1)
args[num_args++].first = i;
}
type_desc.insert(function_name_offset, function_name);
// Second pass: insert argument names before each comma and closing paren.
int i = function_name_offset;
std::string type_desc_with_names(type_desc.begin(),
type_desc.begin() + i);
type_desc_with_names.append(function_name);
for (auto& arg : args) {
if (arg.first < 0) {
LOG_S(ERROR)
<< "When adding argument names to '" << type_desc
<< "', failed to detect positions to insert argument names";
break;
}
if (arg.second.empty())
continue;
// TODO Use inside-out syntax. Note, clang/lib/AST/TypePrinter.cpp does
// not print arg names.
type_desc_with_names.insert(type_desc_with_names.end(), &type_desc[i],
&type_desc[arg.first]);
i = arg.first;
AddName(type_desc_with_names, arg.second);
}
type_desc_with_names.insert(type_desc_with_names.end(),
type_desc.begin() + i, type_desc.end());
type_desc = std::move(type_desc_with_names);
} else {
// type_desc is either a typedef, or some complicated type we cannot handle.
// Append the function_name in this case.
if (type_desc.size() &&
(type_desc.back() != ' ' &&
type_desc.back() != '*' &&
type_desc.back() != '&'))
type_desc.push_back(' ');
type_desc.append(function_name);
AddName(type_desc, function_name);
}
return type_desc;