Browse Source

C/C++: added missing include fixits for std

pipelines/235045657
eidheim 6 years ago
parent
commit
8b19371bdf
  1. 9424
      src/documentation.cpp
  2. 1
      src/documentation.hpp
  3. 16
      src/source.cpp
  4. 4
      src/source.hpp
  5. 99
      src/source_clang.cpp

9424
src/documentation.cpp

File diff suppressed because it is too large Load Diff

1
src/documentation.hpp

@ -4,6 +4,7 @@
namespace Documentation { namespace Documentation {
class CppReference { class CppReference {
public: public:
static std::string get_header(const std::string &symbol) noexcept;
static std::string get_url(const std::string &symbol) noexcept; static std::string get_url(const std::string &symbol) noexcept;
}; };
} // namespace Documentation } // namespace Documentation

16
src/source.cpp

@ -164,8 +164,12 @@ Source::View::View(const boost::filesystem::path &file_path, const Glib::RefPtr<
if(language) { if(language) {
auto language_id = language->get_id(); auto language_id = language->get_id();
if(language_id == "chdr" || language_id == "cpphdr" || language_id == "c" || language_id == "cpp") { if(language_id == "chdr" || language_id == "c")
is_c = true;
else if(language_id == "cpphdr" || language_id == "cpp")
is_cpp = true; is_cpp = true;
if(is_c || is_cpp) {
use_fixed_continuation_indenting = false; use_fixed_continuation_indenting = false;
// TODO 2019: check if clang-format has improved... // TODO 2019: check if clang-format has improved...
// boost::filesystem::path clang_format_file; // boost::filesystem::path clang_format_file;
@ -1520,8 +1524,8 @@ void Source::View::show_or_hide() {
} }
else { else {
auto tabs = tabs_end.get_line_offset() - line_start.get_line_offset(); auto tabs = tabs_end.get_line_offset() - line_start.get_line_offset();
if(is_cpp && tabs == 0 && *line_start == '#') { // C/C++ defines can be at the first line if((is_c || is_cpp) && tabs == 0 && *line_start == '#') { // C/C++ defines can be at the first line
if(end.get_line() == start.get_line()) // Do not try to find define blocks since these rarely are indented if(end.get_line() == start.get_line()) // Do not try to find define blocks since these rarely are indented
break; break;
} }
else if(tabs < start_tabs) { else if(tabs < start_tabs) {
@ -2506,7 +2510,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey *key) {
if(found_tabs_end_iter.get_line_offset() == tabs_end_iter.get_line_offset()) { if(found_tabs_end_iter.get_line_offset() == tabs_end_iter.get_line_offset()) {
has_right_curly_bracket = true; has_right_curly_bracket = true;
// Special case for functions and classes with no indentation after: namespace { // Special case for functions and classes with no indentation after: namespace {
if(is_cpp && tabs_end_iter.starts_line()) { if((is_c || is_cpp) && tabs_end_iter.starts_line()) {
auto iter = condition_iter; auto iter = condition_iter;
Gtk::TextIter open_iter; Gtk::TextIter open_iter;
if(iter.backward_char() && find_open_symbol_backward(iter, open_iter, '{', '}')) { if(iter.backward_char() && find_open_symbol_backward(iter, open_iter, '{', '}')) {
@ -2522,7 +2526,7 @@ bool Source::View::on_key_press_event_bracket_language(GdkEventKey *key) {
// Check if one should add semicolon after '}' // Check if one should add semicolon after '}'
bool add_semicolon = false; bool add_semicolon = false;
if(is_cpp) { if(is_c || is_cpp) {
// add semicolon after class or struct? // add semicolon after class or struct?
auto token = get_token(tabs_end_iter); auto token = get_token(tabs_end_iter);
if(token == "class" || token == "struct") if(token == "class" || token == "struct")
@ -3027,7 +3031,7 @@ bool Source::View::on_key_press_event_smart_inserts(GdkEventKey *key) {
if(found_tabs_end_iter.get_line_offset() == tabs_end_iter.get_line_offset()) { if(found_tabs_end_iter.get_line_offset() == tabs_end_iter.get_line_offset()) {
has_right_curly_bracket = true; has_right_curly_bracket = true;
// Special case for functions and classes with no indentation after: namespace {: // Special case for functions and classes with no indentation after: namespace {:
if(is_cpp && tabs_end_iter.starts_line()) { if((is_c || is_cpp) && tabs_end_iter.starts_line()) {
Gtk::TextIter open_iter; Gtk::TextIter open_iter;
if(find_open_symbol_backward(iter, open_iter, '{', '}')) { if(find_open_symbol_backward(iter, open_iter, '{', '}')) {
if(open_iter.starts_line()) // in case of: namespace test\n{ if(open_iter.starts_line()) // in case of: namespace test\n{

4
src/source.hpp

@ -149,6 +149,9 @@ namespace Source {
bool interactive_completion = true; bool interactive_completion = true;
bool is_c = false;
bool is_cpp = false;
private: private:
void setup_signals(); void setup_signals();
void setup_format_style(bool is_generic_view); void setup_format_style(bool is_generic_view);
@ -158,7 +161,6 @@ namespace Source {
Gsv::GutterRendererText *line_renderer; Gsv::GutterRendererText *line_renderer;
bool use_fixed_continuation_indenting = true; bool use_fixed_continuation_indenting = true;
bool is_cpp = false;
guint previous_non_modifier_keyval = 0; guint previous_non_modifier_keyval = 0;
bool keep_previous_extended_selections = false; bool keep_previous_extended_selections = false;

99
src/source_clang.cpp

@ -292,6 +292,7 @@ void Source::ClangViewParse::update_diagnostics() {
size_t num_warnings = 0; size_t num_warnings = 0;
size_t num_errors = 0; size_t num_errors = 0;
size_t num_fix_its = 0; size_t num_fix_its = 0;
for(auto &diagnostic : clang_diagnostics) { for(auto &diagnostic : clang_diagnostics) {
if(diagnostic.path == file_path.string()) { if(diagnostic.path == file_path.string()) {
int line = diagnostic.offsets.first.line - 1; int line = diagnostic.offsets.first.line - 1;
@ -323,6 +324,103 @@ void Source::ClangViewParse::update_diagnostics() {
error = true; error = true;
} }
// Add include fixits for std
auto get_new_include_offsets = [this]() -> std::pair<clangmm::Offset, clangmm::Offset> {
auto iter = get_buffer()->begin();
auto fallback = iter;
while(iter) {
if(*iter == '#') {
auto next = iter;
if(next.forward_char() && is_token_char(*next)) {
auto token = get_token(next);
if(token == "include")
break;
else if(token == "pragma" && next.forward_to_line_end() && get_buffer()->get_text(iter, next) == "#pragma once" && next.forward_char())
fallback = next;
}
// Move to next preprocessor directive:
while(iter) {
if((!iter.ends_line() && !iter.forward_to_line_end()) || !iter.forward_char() || *iter == '#')
break;
}
}
// Move to next line
else if((!iter.ends_line() && !iter.forward_to_line_end()) || !iter.forward_char())
break;
}
if(!iter) // Use fallback if end of buffer is reached
iter = fallback;
return {{static_cast<unsigned int>(iter.get_line() + 1), static_cast<unsigned int>(iter.get_line_index() + 1)},
{static_cast<unsigned int>(iter.get_line() + 1), static_cast<unsigned int>(iter.get_line_index() + 1)}};
};
auto has_using_namespace_std = [this](size_t token_index) -> bool {
if(token_index + 2 >= clang_tokens->size())
return false;
for(size_t i = 0; i + 2 < token_index; i++) {
if((*clang_tokens)[i].get_kind() == clangmm::Token::Kind::Keyword &&
(*clang_tokens)[i + 1].get_kind() == clangmm::Token::Kind::Keyword &&
(*clang_tokens)[i + 2].get_kind() == clangmm::Token::Kind::Identifier &&
(*clang_tokens)[i].get_spelling() == "using" &&
(*clang_tokens)[i + 1].get_spelling() == "namespace" &&
(*clang_tokens)[i + 2].get_spelling() == "std")
return true;
}
return false;
};
if(diagnostic.fix_its.empty() && diagnostic.severity >= clangmm::Diagnostic::Severity::Error && is_token_char(*start)) {
auto token_string = get_token(start);
for(size_t c = 0; c < clang_tokens->size(); c++) {
auto &token = (*clang_tokens)[c];
if(token.get_kind() == clangmm::Token::Kind::Identifier) {
auto &token_offsets = clang_tokens_offsets[c];
if(static_cast<unsigned int>(line) == token_offsets.first.line - 1 && static_cast<unsigned int>(index) >= token_offsets.first.index - 1 && static_cast<unsigned int>(index) <= token_offsets.second.index - 1) {
if(diagnostic.spelling.compare(0, 44, "implicit instantiation of undefined template") == 0) {
auto cursor = token.get_cursor();
if(cursor.get_referenced()) {
auto type_description = cursor.get_type_description();
bool has_std = false;
if(type_description.compare(0, 5, "std::") == 0) {
has_std = true;
type_description.erase(0, 5);
}
if(type_description.compare(0, 5, "__1::") == 0)
type_description.erase(0, 5);
auto pos = type_description.find('<');
if(pos != std::string::npos)
type_description.erase(pos);
auto header = Documentation::CppReference::get_header(is_cpp && (has_std || has_using_namespace_std(c)) ? "std::" + type_description : type_description);
if(!header.empty())
diagnostic.fix_its.emplace_back(clangmm::Diagnostic::FixIt{"#include <" + header + ">\n", file_path.string(), get_new_include_offsets()});
}
}
if(diagnostic.spelling.compare(0, 17, "unknown type name") == 0 ||
diagnostic.spelling.compare(0, 13, "no type named") == 0 ||
diagnostic.spelling.compare(0, 15, "no member named") == 0 ||
diagnostic.spelling.compare(0, 17, "no template named") == 0 ||
diagnostic.spelling.compare(0, 28, "use of undeclared identifier") == 0 ||
diagnostic.spelling.compare(0, 44, "implicit instantiation of undefined template") == 0 ||
diagnostic.spelling.compare(0, 79, "no viable constructor or deduction guide for deduction of template arguments of") == 0) {
bool has_std = false;
if(token_string == "std" && c + 2 < clang_tokens->size() && (*clang_tokens)[c + 2].get_kind() == clangmm::Token::Kind::Identifier) {
token_string = (*clang_tokens)[c + 2].get_spelling();
has_std = true;
}
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;
auto header = Documentation::CppReference::get_header(is_cpp && (has_std || has_using_namespace_std(c)) ? "std::" + token_string : token_string);
if(!header.empty())
diagnostic.fix_its.emplace_back(clangmm::Diagnostic::FixIt{"#include <" + header + ">\n", file_path.string(), get_new_include_offsets()});
}
break;
}
}
}
}
std::string fix_its_string; std::string fix_its_string;
unsigned fix_its_count = 0; unsigned fix_its_count = 0;
for(auto &fix_it : diagnostic.fix_its) { for(auto &fix_it : diagnostic.fix_its) {
@ -355,6 +453,7 @@ void Source::ClangViewParse::update_diagnostics() {
}); });
} }
} }
status_diagnostics = std::make_tuple(num_warnings, num_errors, num_fix_its); status_diagnostics = std::make_tuple(num_warnings, num_errors, num_fix_its);
if(update_status_diagnostics) if(update_status_diagnostics)
update_status_diagnostics(this); update_status_diagnostics(this);

Loading…
Cancel
Save