Browse Source

Improved C vs C++ include fixits

pipelines/235045657
eidheim 6 years ago
parent
commit
b1141b5583
  1. 14
      src/documentation.cpp
  2. 3
      src/documentation.hpp
  3. 67
      src/source_clang.cpp

14
src/documentation.cpp

@ -1,7 +1,7 @@
#include "documentation.hpp" #include "documentation.hpp"
#include <unordered_map> #include <unordered_map>
std::string Documentation::CppReference::get_header(const std::string &symbol) noexcept { std::vector<std::string> Documentation::CppReference::get_headers(const std::string &symbol) noexcept {
// Extracted from http://upload.cppreference.com/mwiki/images/b/b1/cppreference-doc-20190607.zip // Extracted from http://upload.cppreference.com/mwiki/images/b/b1/cppreference-doc-20190607.zip
// Using raw string instead of map to reduce compile time // Using raw string instead of map to reduce compile time
// Also added: // Also added:
@ -3118,14 +3118,16 @@ std::experimental::filesystem::status_known experimental/filesystem
} }
} }
} }
std::unordered_map<std::string, std::string> map; std::unordered_multimap<std::string, std::string> map;
}; };
static SymbolToHeader symbol_to_header(symbol_headers); static SymbolToHeader symbol_to_header(symbol_headers);
auto it = symbol_to_header.map.find(symbol);
if(it == symbol_to_header.map.end()) std::vector<std::string> results;
return std::string(); auto range = symbol_to_header.map.equal_range(symbol);
return it->second; for(auto it = range.first; it != range.second; ++it)
results.emplace_back(it->second);
return results;
} }
std::string Documentation::CppReference::get_url(const std::string &symbol) noexcept { std::string Documentation::CppReference::get_url(const std::string &symbol) noexcept {

3
src/documentation.hpp

@ -1,10 +1,11 @@
#pragma once #pragma once
#include <string> #include <string>
#include <vector>
namespace Documentation { namespace Documentation {
class CppReference { class CppReference {
public: public:
static std::string get_header(const std::string &symbol) noexcept; static std::vector<std::string> get_headers(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

67
src/source_clang.cpp

@ -367,6 +367,25 @@ void Source::ClangViewParse::update_diagnostics() {
} }
return false; 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)
headers = Documentation::CppReference::get_headers(token);
if(!headers.empty()) {
std::string *c_header = nullptr;
std::string *cpp_header = nullptr;
for(auto &header : headers) {
if(!c_header && header.find(".h") != std::string::npos)
c_header = &header;
else if(!cpp_header)
cpp_header = &header;
}
if(c_header && (is_c || !cpp_header))
diagnostic.fix_its.emplace_back(clangmm::Diagnostic::FixIt{"#include <" + *c_header + ">\n", file_path.string(), get_new_include_offsets()});
else if(cpp_header && is_cpp)
diagnostic.fix_its.emplace_back(clangmm::Diagnostic::FixIt{"#include <" + *cpp_header + ">\n", file_path.string(), get_new_include_offsets()});
}
};
if(diagnostic.fix_its.empty() && diagnostic.severity >= clangmm::Diagnostic::Severity::Error && is_token_char(*start)) { if(diagnostic.fix_its.empty() && diagnostic.severity >= clangmm::Diagnostic::Severity::Error && is_token_char(*start)) {
auto token_string = get_token(start); auto token_string = get_token(start);
for(size_t c = 0; c < clang_tokens->size(); c++) { for(size_t c = 0; c < clang_tokens->size(); c++) {
@ -379,18 +398,19 @@ void Source::ClangViewParse::update_diagnostics() {
if(cursor.get_referenced()) { if(cursor.get_referenced()) {
auto type_description = cursor.get_type_description(); auto type_description = cursor.get_type_description();
bool has_std = false; bool has_std = false;
if(type_description.compare(0, 5, "std::") == 0) { if(is_cpp) {
has_std = true; if(type_description.compare(0, 5, "std::") == 0) {
type_description.erase(0, 5); 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);
} }
if(type_description.compare(0, 5, "__1::") == 0)
type_description.erase(0, 5); add_include_fixit(has_std, is_cpp && has_using_namespace_std(c), type_description);
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 || if(diagnostic.spelling.compare(0, 17, "unknown type name") == 0 ||
@ -401,19 +421,20 @@ void Source::ClangViewParse::update_diagnostics() {
diagnostic.spelling.compare(0, 44, "implicit instantiation of undefined template") == 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) { diagnostic.spelling.compare(0, 79, "no viable constructor or deduction guide for deduction of template arguments of") == 0) {
bool has_std = false; bool has_std = false;
if(token_string == "std" && c + 2 < clang_tokens->size() && (*clang_tokens)[c + 2].get_kind() == clangmm::Token::Kind::Identifier) { if(is_cpp) {
token_string = (*clang_tokens)[c + 2].get_spelling(); if(token_string == "std" && c + 2 < clang_tokens->size() && (*clang_tokens)[c + 2].get_kind() == clangmm::Token::Kind::Identifier) {
has_std = true; 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;
} }
else if(c >= 2 &&
(*clang_tokens)[c - 1].get_kind() == clangmm::Token::Punctuation && add_include_fixit(has_std, is_cpp && has_using_namespace_std(c), token_string);
(*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; break;
} }

Loading…
Cancel
Save