mirror of
				https://github.com/MaskRay/ccls.git
				synced 2025-11-03 22:04:24 +00:00 
			
		
		
		
	Refactor function signatures: fix infinite loop processing constructors
This commit is contained in:
		
							parent
							
								
									8bdce31789
								
							
						
					
					
						commit
						6fa08b2b90
					
				
							
								
								
									
										153
									
								
								src/indexer.cc
									
									
									
									
									
								
							
							
						
						
									
										153
									
								
								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<std::string> 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<std::pair<int, std::string>> 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
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user