Browse Source

Significantly improved reparsing speed of C/C++ header files by removing include guard before passing the file content to libclang

merge-requests/365/head
eidheim 9 years ago
parent
commit
9872a18cb4
  1. 99
      src/source_clang.cc
  2. 2
      src/source_clang.h
  3. 47
      tests/source_clang_test.cc

99
src/source_clang.cc

@ -104,7 +104,9 @@ void Source::ClangViewParse::parse_initialize() {
} }
pos++; pos++;
} }
clang_tu = std::make_unique<clang::TranslationUnit>(clang_index, file_path.string(), get_compilation_commands(), buffer.raw()); auto &buffer_raw=const_cast<std::string&>(buffer.raw());
remove_include_guard(buffer_raw);
clang_tu = std::make_unique<clang::TranslationUnit>(clang_index, file_path.string(), get_compilation_commands(), buffer_raw);
clang_tokens=clang_tu->get_tokens(0, buffer.bytes()-1); clang_tokens=clang_tu->get_tokens(0, buffer.bytes()-1);
update_syntax(); update_syntax();
@ -133,7 +135,9 @@ void Source::ClangViewParse::parse_initialize() {
}); });
} }
else if (parse_process_state==ParseProcessState::PROCESSING && parse_lock.try_lock()) { else if (parse_process_state==ParseProcessState::PROCESSING && parse_lock.try_lock()) {
auto status=clang_tu->ReparseTranslationUnit(parse_thread_buffer.raw()); auto &parse_thread_buffer_raw=const_cast<std::string&>(parse_thread_buffer.raw());
remove_include_guard(parse_thread_buffer_raw);
auto status=clang_tu->ReparseTranslationUnit(parse_thread_buffer_raw);
parsing_in_progress->done("done"); parsing_in_progress->done("done");
if(status==0) { if(status==0) {
auto expected=ParseProcessState::PROCESSING; auto expected=ParseProcessState::PROCESSING;
@ -244,6 +248,92 @@ std::vector<std::string> Source::ClangViewParse::get_compilation_commands() {
return arguments; return arguments;
} }
void Source::ClangViewParse::remove_include_guard(std::string &buffer) {
if(!(language && (language->get_id()=="chdr" || language->get_id()=="cpphdr")))
return;
static std::regex ifndef_regex("^[ \t]*#ifndef.*$");
static std::regex define_regex("^[ \t]*#define.*$");
static std::regex endif_regex("^[ \t]*#endif.*$");
std::vector<std::pair<size_t, size_t>> ranges;
bool found_ifndef=false, found_define=false;
bool line_comment=false, multiline_comment=false;
size_t start_of_line=0;
std::string line;
for(size_t c=0;c<buffer.size();++c) {
if(!line_comment && !multiline_comment && buffer[c]=='/') {
if(c+1<buffer.size()) {
if(buffer[c+1]=='/')
line_comment=true;
else if(buffer[c+1]=='*')
multiline_comment=true;
}
}
else if(multiline_comment && buffer[c]=='*') {
if(c+1<buffer.size() && buffer[c+1]=='/')
multiline_comment=false;
}
else if(buffer[c]=='\n') {
bool empty_line=true;
for(auto &chr: line) {
if(chr!=' ' && chr!='\t') {
empty_line=false;
break;
}
}
std::smatch sm;
if(empty_line) {}
else if(!found_ifndef && std::regex_match(line, sm, ifndef_regex)) {
found_ifndef=true;
ranges.emplace_back(start_of_line, c);
}
else if(found_ifndef && std::regex_match(line, sm, define_regex)) {
found_define=true;
ranges.emplace_back(start_of_line, c);
break;
}
else
return;
line_comment=false;
line.clear();
if(c+1<buffer.size())
start_of_line=c+1;
else
return;
}
else if(buffer[c]!='\r' && !line_comment && !multiline_comment)
line+=buffer[c];
}
if(found_ifndef && found_define) {
size_t last_char_pos=std::string::npos;
for(size_t c=buffer.size()-1;c!=std::string::npos;--c) {
if(last_char_pos==std::string::npos) {
if(buffer[c]!=' ' && buffer[c]!='\t' && buffer[c]!='\r' && buffer[c]!='\n')
last_char_pos=c;
}
else {
if(buffer[c]=='\n' && c+1<buffer.size()) {
auto line=buffer.substr(c+1, last_char_pos-c);
std::smatch sm;
if(std::regex_match(line, sm, endif_regex)) {
ranges.emplace_back(c+1, last_char_pos+1);
for(auto &range: ranges) {
for(size_t c=range.first;c<range.second;++c) {
if(buffer[c]!='\r')
buffer[c]=' ';
}
}
return;
}
return;
}
}
}
}
}
void Source::ClangViewParse::update_syntax() { void Source::ClangViewParse::update_syntax() {
auto buffer=get_buffer(); auto buffer=get_buffer();
const auto apply_tag=[this, buffer](const std::pair<clang::Offset, clang::Offset> &offsets, int type) { const auto apply_tag=[this, buffer](const std::pair<clang::Offset, clang::Offset> &offsets, int type) {
@ -689,7 +779,10 @@ void Source::ClangViewAutocomplete::autocomplete() {
std::unique_lock<std::mutex> lock(parse_mutex); std::unique_lock<std::mutex> lock(parse_mutex);
if(parse_state==ParseState::PROCESSING) { if(parse_state==ParseState::PROCESSING) {
parse_process_state=ParseProcessState::IDLE; parse_process_state=ParseProcessState::IDLE;
auto autocomplete_data=std::make_shared<std::vector<AutoCompleteData> >(autocomplete_get_suggestions(buffer->raw(), line_nr, column_nr));
auto &buffer_raw=const_cast<std::string&>(buffer->raw());
remove_include_guard(buffer_raw);
auto autocomplete_data=std::make_shared<std::vector<AutoCompleteData> >(autocomplete_get_suggestions(buffer_raw, line_nr, column_nr));
if(parse_state==ParseState::PROCESSING) { if(parse_state==ParseState::PROCESSING) {
dispatcher.post([this, autocomplete_data] { dispatcher.post([this, autocomplete_data] {

2
src/source_clang.h

@ -32,6 +32,8 @@ namespace Source {
std::shared_ptr<Terminal::InProgress> parsing_in_progress; std::shared_ptr<Terminal::InProgress> parsing_in_progress;
void remove_include_guard(std::string &buffer);
void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) override; void show_diagnostic_tooltips(const Gdk::Rectangle &rectangle) override;
void show_type_tooltips(const Gdk::Rectangle &rectangle) override; void show_type_tooltips(const Gdk::Rectangle &rectangle) override;

47
tests/source_clang_test.cc

@ -80,6 +80,53 @@ int main() {
g_assert_cmpuint(clang_view->clang_diagnostics.size(), >, 0); g_assert_cmpuint(clang_view->clang_diagnostics.size(), >, 0);
g_assert_cmpuint(clang_view->get_fix_its().size(), >, 0); g_assert_cmpuint(clang_view->get_fix_its().size(), >, 0);
// test remove_include_guard
{
clang_view->language=Gsv::LanguageManager::get_default()->get_language("chdr");
std::string source="#ifndef F\n#define F\n#endif // F";
clang_view->remove_include_guard(source);
g_assert_cmpstr(source.c_str(),==," \n \n ");
source="#ifndef F\n#define F\n#endif // F\n";
clang_view->remove_include_guard(source);
g_assert_cmpstr(source.c_str(),==," \n \n \n");
source="/*test*/\n#ifndef F\n#define F\n#endif // F\n";
clang_view->remove_include_guard(source);
g_assert_cmpstr(source.c_str(),==,"/*test*/\n \n \n \n");
source="//test\n#ifndef F\n#define F\n#endif // F\n";
clang_view->remove_include_guard(source);
g_assert_cmpstr(source.c_str(),==,"//test\n \n \n \n");
source="#ifndef F /*test*/\n#define F\n#endif // F";
clang_view->remove_include_guard(source);
g_assert_cmpstr(source.c_str(),==," \n \n ");
source="#ifndef F //test\n#define F\n#endif // F";
clang_view->remove_include_guard(source);
g_assert_cmpstr(source.c_str(),==," \n \n ");
source="#ifndef F\n//test\n#define F\n#endif // F\n";
clang_view->remove_include_guard(source);
g_assert_cmpstr(source.c_str(),==," \n//test\n \n \n");
source="#ifndef F\ntest\n#define F\n#endif // F\n";
auto old_source=source;
clang_view->remove_include_guard(source);
g_assert_cmpstr(old_source.c_str(),==,source.c_str());
source="test\n#ifndef F\n#define F\n#endif // F\n";
old_source=source;
clang_view->remove_include_guard(source);
g_assert_cmpstr(old_source.c_str(),==,source.c_str());
source="#ifndef F\n#define F\n#endif // F\ntest\n";
old_source=source;
clang_view->remove_include_guard(source);
g_assert_cmpstr(old_source.c_str(),==,source.c_str());
}
clang_view->async_delete(); clang_view->async_delete();
clang_view->delete_thread.join(); clang_view->delete_thread.join();
flush_events(); flush_events();

Loading…
Cancel
Save