From 4e121ffd00336d0b9262b0321b9eb9ec4d372323 Mon Sep 17 00:00:00 2001 From: eidheim Date: Fri, 18 Jun 2021 14:33:45 +0200 Subject: [PATCH] Improved C/C++ include fixits --- src/source_clang.cpp | 60 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 48 insertions(+), 12 deletions(-) diff --git a/src/source_clang.cpp b/src/source_clang.cpp index 3f4e32a..c77596d 100644 --- a/src/source_clang.cpp +++ b/src/source_clang.cpp @@ -370,9 +370,11 @@ void Source::ClangViewParse::update_diagnostics() { } return false; }; - auto add_include_fixit = [this, &diagnostic, &get_new_include_offsets](bool has_std, bool has_using_std, const std::string &token) { - auto headers = Documentation::CppReference::get_headers(has_std || has_using_std ? "std::" + token : token); - if(headers.empty() && !has_std && has_using_std) + auto add_include_fixit = [this, &diagnostic, &get_new_include_offsets](std::string ns, bool has_using_std, const std::string &token) { + auto headers = Documentation::CppReference::get_headers(!ns.empty() ? ns + "::" + token : (has_using_std ? "std::" + token : token)); + if(headers.empty() && !ns.empty() && ns != "std" && !starts_with(ns, "std::") && has_using_std) + headers = Documentation::CppReference::get_headers("std::" + ns + "::" + token); + if(headers.empty() && ns.empty() && has_using_std) headers = Documentation::CppReference::get_headers(token); if(!headers.empty()) { std::string *c_header = nullptr; @@ -403,20 +405,37 @@ void Source::ClangViewParse::update_diagnostics() { end = diagnostic.spelling.find('\'', start); if(end != std::string::npos) { auto type = diagnostic.spelling.substr(start, end - start); - bool has_std = false; + std::string ns; if(is_cpp) { if(starts_with(type, "std::")) { - has_std = true; + ns = "std"; type.erase(0, 5); } if(starts_with(type, "__1::")) type.erase(0, 5); } - add_include_fixit(has_std, is_cpp && has_using_namespace_std(c), type); + add_include_fixit(ns, is_cpp && has_using_namespace_std(c), type); break; } } } + if(diagnostic.severity >= clangmm::Diagnostic::Severity::Error && + starts_with(diagnostic.spelling, "variable has incomplete type '")) { + size_t start = 30; + auto end = diagnostic.spelling.find('\'', start); + if(end != std::string::npos) { + auto type = diagnostic.spelling.substr(start, end - start); + std::string ns; + if(is_cpp) { + if(starts_with(type, "std::")) { + ns = "std"; + type.erase(0, 5); + } + } + add_include_fixit(ns, is_cpp && has_using_namespace_std(c), type); + break; + } + } if(is_token_char(*start) && token.get_kind() == clangmm::Token::Kind::Identifier) { if(diagnostic.severity >= clangmm::Diagnostic::Severity::Error && (starts_with(diagnostic.spelling, "unknown type name") || @@ -427,24 +446,41 @@ void Source::ClangViewParse::update_diagnostics() { starts_with(diagnostic.spelling, "implicit instantiation of undefined template") || starts_with(diagnostic.spelling, "no viable constructor or deduction guide for deduction of template arguments of"))) { auto token_string = get_token(start); - bool has_std = false; + std::string ns; if(is_cpp) { - if(token_string == "std" && c + 2 < clang_tokens->size() && (*clang_tokens)[c + 2].get_kind() == clangmm::Token::Kind::Identifier) { + if(token_string == "std" && c + 2 < clang_tokens->size() && + (*clang_tokens)[c + 1].get_kind() == clangmm::Token::Punctuation && + (*clang_tokens)[c + 2].get_kind() == clangmm::Token::Identifier && + (*clang_tokens)[c + 1].get_spelling() == "::") { token_string = (*clang_tokens)[c + 2].get_spelling(); - has_std = true; + ns = "std"; } else if(c >= 2 && (*clang_tokens)[c - 1].get_kind() == clangmm::Token::Punctuation && (*clang_tokens)[c - 2].get_kind() == clangmm::Token::Identifier && (*clang_tokens)[c - 1].get_spelling() == "::" && (*clang_tokens)[c - 2].get_spelling() == "std") - has_std = true; + ns = "std"; + else if(c >= 4 && + (*clang_tokens)[c - 1].get_kind() == clangmm::Token::Punctuation && + (*clang_tokens)[c - 2].get_kind() == clangmm::Token::Identifier && + (*clang_tokens)[c - 3].get_kind() == clangmm::Token::Punctuation && + (*clang_tokens)[c - 4].get_kind() == clangmm::Token::Identifier && + (*clang_tokens)[c - 1].get_spelling() == "::" && + (*clang_tokens)[c - 3].get_spelling() == "::" && + (*clang_tokens)[c - 4].get_spelling() == "std") + ns = "std::" + (*clang_tokens)[c - 2].get_spelling(); + else if(c >= 2 && + (*clang_tokens)[c - 1].get_kind() == clangmm::Token::Punctuation && + (*clang_tokens)[c - 2].get_kind() == clangmm::Token::Identifier && + (*clang_tokens)[c - 1].get_spelling() == "::") + ns = (*clang_tokens)[c - 2].get_spelling(); } - add_include_fixit(has_std, is_cpp && has_using_namespace_std(c), token_string); + add_include_fixit(ns, is_cpp && has_using_namespace_std(c), token_string); } else if(diagnostic.severity >= clangmm::Diagnostic::Severity::Warning && is_c && starts_with(diagnostic.spelling, "implicitly declaring library function")) - add_include_fixit(false, false, get_token(start)); + add_include_fixit("", false, get_token(start)); } break; }