diff --git a/src/indexer.cc b/src/indexer.cc index dd5dea09..d93dd2d1 100644 --- a/src/indexer.cc +++ b/src/indexer.cc @@ -1070,110 +1070,109 @@ ClangCursor::VisitResult TemplateVisitor(ClangCursor cursor, return ClangCursor::VisitResult::Continue; } -} // namespace - // Build a detailed function signature, including argument names. -static std::string get_function_signature(IndexFile* db, - NamespaceHelper* ns, - const CXIdxDeclInfo* decl) { +std::string GetFunctionSignature(IndexFile* db, + NamespaceHelper* ns, + const CXIdxDeclInfo* decl) { // Build the function name, with scope and parameters - ClangCursor decl_cursor = decl->cursor; - std::string type_desc = decl_cursor.get_type_description(); - int args_num = clang_Cursor_getNumArguments(decl->cursor); + std::string type_desc = ClangCursor(decl->cursor).get_type_description(); + int num_args = clang_Cursor_getNumArguments(decl->cursor); std::string function_name = ns->QualifiedName(decl->semanticContainer, decl->entityInfo->name); - std::vector arg_names; - for (int i = 0; i < args_num; i++) { - CXCursor arg = clang_Cursor_getArgument(decl->cursor, i); - auto id = ::ToString(clang_getCursorDisplayName(arg)); - arg_names.push_back(id); + std::vector> args; + for (int i = 0; i < num_args; i++) { + args.emplace_back(-1, ::ToString(clang_getCursorDisplayName( + clang_Cursor_getArgument(decl->cursor, i)))); } - if (clang_Cursor_isVariadic(decl->cursor)) { - arg_names.push_back(""); - args_num++; + args.emplace_back(-1, ""); + num_args++; } - size_t balance = 0, offset; - size_t closing_bracket_offset = 0; + int function_name_offset = -1; // Scan the function type backwards. - // First pass: find the position of the closing bracket in the type. - for (offset = type_desc.size(); offset;) { - offset--; - // Remember that ) was seen. - if (type_desc[offset] == ')') { + for (int balance = 0, i = int(type_desc.size()); i--; ) { + if (type_desc[i] == ')') balance++; - if (balance == 1) { - closing_bracket_offset = offset; - } - } // Balanced paren pair that may appear before the paren enclosing // function parameters, see clang/lib/AST/TypePrinter.cpp - else if (type_desc[offset] == '(' && --balance == 0 && - !((offset >= 5 && !type_desc.compare(offset - 5, 5, "throw")) || - (offset >= 6 && !type_desc.compare(offset - 6, 6, "typeof")) || - (offset >= 7 && !type_desc.compare(offset - 7, 7, "_Atomic")) || - (offset >= 8 && !type_desc.compare(offset - 8, 8, "decltype")) || - (offset >= 8 && !type_desc.compare(offset - 8, 8, "noexcept")) || - (offset >= 13 && - !type_desc.compare(offset - 13, 13, "__attribute__")))) + else if (type_desc[i] == '(' && --balance == 0 && + !((i >= 5 && !type_desc.compare(i - 5, 5, "throw")) || + (i >= 6 && !type_desc.compare(i - 6, 6, "typeof")) || + (i >= 7 && !type_desc.compare(i - 7, 7, "_Atomic")) || + (i >= 8 && !type_desc.compare(i - 8, 8, "decltype")) || + (i >= 8 && !type_desc.compare(i - 8, 8, "noexcept")) || + (i >= 13 && + !type_desc.compare(i - 13, 13, "__attribute__")))) { + // Do not bother with function types which return function pointers. + if (type_desc.find("(*") >= std::string::size_type(i)) + function_name_offset = i; break; + } } + //volatile int z=0;while(!z)asm("pause"); - size_t function_name_offset = offset; - - if (closing_bracket_offset > 0) { - // Insert the name of the last parameter right before the closing bracket. - int arg_idx = args_num - 1; - if (args_num > 0) { - if (!arg_names[arg_idx].empty()) { - type_desc.insert(closing_bracket_offset, arg_names[arg_idx]); - // Insert a space between the type and the argument name if required. - if (!isspace(type_desc[closing_bracket_offset - 1]) && - type_desc[closing_bracket_offset - 1] != '*' && - type_desc[closing_bracket_offset - 1] != '&') - type_desc.insert(closing_bracket_offset, " "); + if (function_name_offset >= 0) { + 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] == '<' || type_desc[i] == '[') + balance++; + else if (type_desc[i] == ')' || 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; } - arg_idx--; + + // 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"; + break; + } + if (arg.second.empty()) continue; + 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); } - balance = 1; - // Second pass: Insert argument names before each comma. - for (offset = closing_bracket_offset; - offset >= function_name_offset && args_num > 0;) { - offset--; - // Remember that ) was seen. - if (type_desc[offset] == ')' || type_desc[offset] == '>' || - type_desc[offset] == ']' || type_desc[offset] == '}') { - balance++; - } else if (type_desc[offset] == ',' && balance == 1) { - if (!arg_names[arg_idx].empty()) { - type_desc.insert(offset, arg_names[arg_idx]); - // Insert a space between the type and the argument name if required. - if (!isspace(type_desc[offset - 1]) && type_desc[offset - 1] != '*' && - type_desc[offset - 1] != '&') - type_desc.insert(offset, " "); - } - arg_idx--; - } else if (type_desc[offset] == '<' || type_desc[offset] == '[' || - type_desc[offset] == '{') - balance--; - else if (type_desc[offset] == '(' && --balance == 0) - break; - } - } - if (function_name_offset > 0) { + // TODO auto f() -> int(*)() ; int(*f())() type_desc.insert(function_name_offset, function_name); } else { - type_desc.append(" " + function_name); + // type_desc is either a typedef, or some complicated type we cannot handle. + // Append the function_name in this case. + type_desc.push_back(' '); + type_desc.append(function_name); } return type_desc; } +} // namespace + void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { if (!kIndexStdDeclarations && clang_Location_isInSystemHeader( @@ -1412,7 +1411,7 @@ void OnIndexDeclaration(CXClientData client_data, const CXIdxDeclInfo* decl) { // Build detailed name. The type desc looks like void (void *). We // insert the qualified name before the first '('. - func->def.detailed_name = get_function_signature(db, ns, decl); + func->def.detailed_name = GetFunctionSignature(db, ns, decl); // CXCursor_OverloadedDeclRef in templates are not processed by // OnIndexReference, thus we use TemplateVisitor to collect function