diff --git a/CMakeLists.txt b/CMakeLists.txt index 818eb71c..0594e2ba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -210,7 +210,6 @@ target_sources(ccls PRIVATE src/config.cc src/diagnostics_engine.cc src/file_consumer.cc - src/file_contents.cc src/filesystem.cc src/fuzzy_match.cc src/iindexer.cc diff --git a/src/clang_cursor.cc b/src/clang_cursor.cc index efb297c4..369da744 100644 --- a/src/clang_cursor.cc +++ b/src/clang_cursor.cc @@ -17,8 +17,8 @@ Range ResolveCXSourceRange(const CXSourceRange& range, CXFile* cx_file) { unsigned int end_line, end_column; clang_getSpellingLocation(end, nullptr, &end_line, &end_column, nullptr); - return Range(Position((int16_t)start_line - 1, (int16_t)start_column - 1), - Position((int16_t)end_line - 1, (int16_t)end_column - 1)); + return Range{{int16_t(start_line - 1), (int16_t)(start_column - 1)}, + {int16_t(end_line - 1), int16_t(end_column - 1)}}; } ClangCursor ClangType::get_declaration() const { diff --git a/src/clang_indexer.cc b/src/clang_indexer.cc index b03ef730..e335a750 100644 --- a/src/clang_indexer.cc +++ b/src/clang_indexer.cc @@ -9,6 +9,7 @@ #include +#include #include #include #include @@ -280,7 +281,7 @@ struct ConstructorCache { struct IndexParam { std::unordered_set seen_cx_files; std::vector seen_files; - FileContentsMap file_contents; + std::unordered_map file_contents; std::unordered_map file_modification_times; // Only use this when strictly needed (ie, primary translation unit is @@ -729,7 +730,10 @@ IndexTypeId IndexFile::ToTypeId(Usr usr) { return it->second; IndexTypeId id(types.size()); - types.push_back(IndexType(id, usr)); + IndexType type; + type.usr = usr; + type.id = id; + types.push_back(type); id_cache.usr_to_type_id[usr] = id; id_cache.type_id_to_usr[id] = usr; return id; @@ -740,7 +744,10 @@ IndexFuncId IndexFile::ToFuncId(Usr usr) { return it->second; IndexFuncId id(funcs.size()); - funcs.push_back(IndexFunc(id, usr)); + IndexFunc func; + func.usr = usr; + func.id = id; + funcs.push_back(std::move(func)); id_cache.usr_to_func_id[usr] = id; id_cache.func_id_to_usr[id] = usr; return id; @@ -751,7 +758,10 @@ IndexVarId IndexFile::ToVarId(Usr usr) { return it->second; IndexVarId id(vars.size()); - vars.push_back(IndexVar(id, usr)); + IndexVar var; + var.usr = usr; + var.id = id; + vars.push_back(std::move(var)); id_cache.usr_to_var_id[usr] = id; id_cache.var_id_to_usr[id] = usr; return id; @@ -783,8 +793,6 @@ std::string IndexFile::ToString() { return Serialize(SerializeFormat::Json, *this); } -IndexType::IndexType(IndexTypeId id, Usr usr) : usr(usr), id(id) {} - template void Uniquify(std::vector>& ids) { std::unordered_set> seen; @@ -796,11 +804,19 @@ void Uniquify(std::vector>& ids) { } void Uniquify(std::vector& uses) { - std::unordered_set seen; + union U { + Range range = {}; + uint64_t u64; + }; + static_assert(sizeof(Range) == 8); + std::unordered_set seen; size_t n = 0; - for (size_t i = 0; i < uses.size(); i++) - if (seen.insert(uses[i].range).second) + for (size_t i = 0; i < uses.size(); i++) { + U u; + u.range = uses[i].range; + if (seen.insert(u.u64).second) uses[n++] = uses[i]; + } uses.resize(n); } @@ -2343,10 +2359,6 @@ void IndexInit() { clang_toggleCrashRecovery(1); } -std::string GetClangVersion() { - return ToString(clang_getClangVersion()); -} - // |SymbolRef| is serialized this way. // |Use| also uses this though it has an extra field |file|, // which is not used by Index* so it does not need to be serialized. @@ -2354,7 +2366,7 @@ void Reflect(Reader& visitor, Reference& value) { if (visitor.Format() == SerializeFormat::Json) { std::string t = visitor.GetString(); char* s = const_cast(t.c_str()); - value.range = Range(s); + value.range = Range::FromString(s); s = strchr(s, '|'); value.id.id = RawId(strtol(s + 1, &s, 10)); value.kind = static_cast(strtol(s + 1, &s, 10)); @@ -2368,12 +2380,13 @@ void Reflect(Reader& visitor, Reference& value) { } void Reflect(Writer& visitor, Reference& value) { if (visitor.Format() == SerializeFormat::Json) { - std::string s = value.range.ToString(); // RawId(-1) -> "-1" - s += '|' + std::to_string( - static_cast::type>(value.id.id)); - s += '|' + std::to_string(int(value.kind)); - s += '|' + std::to_string(int(value.role)); + char buf[99]; + snprintf(buf, sizeof buf, "%s|%" PRId32 "|%d|%d", + value.range.ToString().c_str(), + static_cast::type>(value.id.id), + int(value.kind), int(value.role)); + std::string s(buf); Reflect(visitor, s); } else { Reflect(visitor, value.range); diff --git a/src/file_consumer.cc b/src/file_consumer.cc index c237c5b7..9d1d276a 100644 --- a/src/file_consumer.cc +++ b/src/file_consumer.cc @@ -9,8 +9,9 @@ namespace { -std::optional GetFileContents(const std::string& path, - FileContentsMap* file_contents) { +std::optional GetFileContents( + const std::string& path, + std::unordered_map* file_contents) { auto it = file_contents->find(path); if (it == file_contents->end()) { std::optional content = ReadContent(path); @@ -28,6 +29,34 @@ bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b) { a.data[2] == b.data[2]; } +FileContents::FileContents() : line_offsets_{0} {} + +FileContents::FileContents(const std::string& path, const std::string& content) + : path(path), content(content) { + line_offsets_.push_back(0); + for (size_t i = 0; i < content.size(); i++) { + if (content[i] == '\n') + line_offsets_.push_back(i + 1); + } +} + +std::optional FileContents::ToOffset(Position p) const { + if (0 <= p.line && size_t(p.line) < line_offsets_.size()) { + int ret = line_offsets_[p.line] + p.column; + if (size_t(ret) < content.size()) + return ret; + } + return std::nullopt; +} + +std::optional FileContents::ContentsInRange(Range range) const { + std::optional start_offset = ToOffset(range.start), + end_offset = ToOffset(range.end); + if (start_offset && end_offset && *start_offset < *end_offset) + return content.substr(*start_offset, *end_offset - *start_offset); + return std::nullopt; +} + bool FileConsumerSharedState::Mark(const std::string& file) { std::lock_guard lock(mutex); return used_files.insert(file).second; @@ -44,9 +73,10 @@ FileConsumer::FileConsumer(FileConsumerSharedState* shared_state, const std::string& parse_file) : shared_(shared_state), parse_file_(parse_file) {} -IndexFile* FileConsumer::TryConsumeFile(CXFile file, - bool* is_first_ownership, - FileContentsMap* file_contents_map) { +IndexFile* FileConsumer::TryConsumeFile( + CXFile file, + bool* is_first_ownership, + std::unordered_map* file_contents_map) { assert(is_first_ownership); CXFileUniqueID file_id; diff --git a/src/file_consumer.h b/src/file_consumer.h index 6ac94edd..de7162c3 100644 --- a/src/file_consumer.h +++ b/src/file_consumer.h @@ -1,6 +1,6 @@ #pragma once -#include "file_contents.h" +#include "position.h" #include "utils.h" #include @@ -9,6 +9,7 @@ #include #include #include +#include struct IndexFile; @@ -16,6 +17,19 @@ struct IndexFile; MAKE_HASHABLE(CXFileUniqueID, t.data[0], t.data[1], t.data[2]); bool operator==(const CXFileUniqueID& a, const CXFileUniqueID& b); +struct FileContents { + FileContents(); + FileContents(const std::string& path, const std::string& content); + + std::optional ToOffset(Position p) const; + std::optional ContentsInRange(Range range) const; + + std::string path; + std::string content; + // {0, 1 + position of first newline, 1 + position of second newline, ...} + std::vector line_offsets_; +}; + struct FileConsumerSharedState { mutable std::unordered_set used_files; mutable std::mutex mutex; @@ -48,7 +62,7 @@ struct FileConsumer { // variable since it is large and we do not want to copy it. IndexFile* TryConsumeFile(CXFile file, bool* is_first_ownership, - FileContentsMap* file_contents); + std::unordered_map* file_contents); // Returns and passes ownership of all local state. std::vector> TakeLocalState(); @@ -59,4 +73,4 @@ struct FileConsumer { std::unordered_map> local_; FileConsumerSharedState* shared_; std::string parse_file_; -}; \ No newline at end of file +}; diff --git a/src/file_contents.cc b/src/file_contents.cc deleted file mode 100644 index 5a7bc0f4..00000000 --- a/src/file_contents.cc +++ /dev/null @@ -1,29 +0,0 @@ -#include "file_contents.h" - -FileContents::FileContents() : line_offsets_{0} {} - -FileContents::FileContents(const std::string& path, const std::string& content) - : path(path), content(content) { - line_offsets_.push_back(0); - for (size_t i = 0; i < content.size(); i++) { - if (content[i] == '\n') - line_offsets_.push_back(i + 1); - } -} - -std::optional FileContents::ToOffset(Position p) const { - if (0 <= p.line && size_t(p.line) < line_offsets_.size()) { - int ret = line_offsets_[p.line] + p.column; - if (size_t(ret) < content.size()) - return ret; - } - return std::nullopt; -} - -std::optional FileContents::ContentsInRange(Range range) const { - std::optional start_offset = ToOffset(range.start), - end_offset = ToOffset(range.end); - if (start_offset && end_offset && *start_offset < *end_offset) - return content.substr(*start_offset, *end_offset - *start_offset); - return std::nullopt; -} diff --git a/src/file_contents.h b/src/file_contents.h deleted file mode 100644 index 21c484d4..00000000 --- a/src/file_contents.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include "position.h" - -#include -#include -#include -#include - -struct FileContents { - FileContents(); - FileContents(const std::string& path, const std::string& content); - - std::optional ToOffset(Position p) const; - std::optional ContentsInRange(Range range) const; - - std::string path; - std::string content; - // {0, 1 + position of first newline, 1 + position of second newline, ...} - std::vector line_offsets_; -}; - -using FileContentsMap = std::unordered_map; diff --git a/src/indexer.h b/src/indexer.h index a57febe1..05c8e610 100644 --- a/src/indexer.h +++ b/src/indexer.h @@ -4,7 +4,6 @@ #include "clang_translation_unit.h" #include "clang_utils.h" #include "file_consumer.h" -#include "file_contents.h" #include "language.h" #include "lsp.h" #include "maybe.h" @@ -54,7 +53,7 @@ struct Id { // Needed for google::dense_hash_map. explicit operator RawId() const { return id; } - bool HasValueForMaybe_() const { return id != RawId(-1); } + bool Valid() const { return id != RawId(-1); } bool operator==(const Id& o) const { return id == o.id; } bool operator!=(const Id& o) const { return id != o.id; } @@ -101,7 +100,7 @@ struct Reference { SymbolKind kind; Role role; - bool HasValueForMaybe_() const { return range.HasValueForMaybe_(); } + bool Valid() const { return range.Valid(); } operator SymbolIdx() const { return {id, kind}; } std::tuple, SymbolKind, Role> ToTuple() const { return std::make_tuple(range, id, kind, role); @@ -126,8 +125,6 @@ struct Use : Reference { Use(Range range, Id id, SymbolKind kind, Role role, Id file) : Reference{range, id, kind, role}, file(file) {} }; -// Used by |HANDLE_MERGEABLE| so only |range| is needed. -MAKE_HASHABLE(Use, t.range); void Reflect(Reader& visitor, Reference& value); void Reflect(Writer& visitor, Reference& value); @@ -241,9 +238,6 @@ struct IndexType { // NOTE: Do not insert directly! Use AddUsage instead. std::vector uses; - IndexType() {} // For serialization. - IndexType(IndexTypeId id, Usr usr); - bool operator<(const IndexType& other) const { return id < other.id; } }; MAKE_HASHABLE(IndexType, t.id); @@ -336,9 +330,6 @@ struct IndexFunc : NameMixin { // def.spell. std::vector uses; - IndexFunc() {} // For serialization. - IndexFunc(IndexFuncId id, Usr usr) : usr(usr), id(id) {} - bool operator<(const IndexFunc& other) const { return id < other.id; } }; MAKE_HASHABLE(IndexFunc, t.id); @@ -408,9 +399,6 @@ struct IndexVar { std::vector declarations; std::vector uses; - IndexVar() {} // For serialization. - IndexVar(IndexVarId id, Usr usr) : usr(usr), id(id) {} - bool operator<(const IndexVar& other) const { return id < other.id; } }; MAKE_HASHABLE(IndexVar, t.id); @@ -519,7 +507,3 @@ std::vector> ParseWithTu( bool ConcatTypeAndName(std::string& type, const std::string& name); void IndexInit(); - -void ClangSanityCheck(); - -std::string GetClangVersion(); diff --git a/src/maybe.h b/src/maybe.h index c26c9708..328fc71e 100644 --- a/src/maybe.h +++ b/src/maybe.h @@ -5,7 +5,7 @@ #include // Like std::optional, but the stored data is responsible for containing the empty -// state. T should define a function `bool T::HasValueForMaybe_()`. +// state. T should define a function `bool T::Valid()`. template class Maybe { T storage; @@ -28,10 +28,10 @@ class Maybe { const T& operator*() const { return storage; } T& operator*() { return storage; } - bool HasValue() const { return storage.HasValueForMaybe_(); } - explicit operator bool() const { return HasValue(); } + bool Valid() const { return storage.Valid(); } + explicit operator bool() const { return Valid(); } operator std::optional() const { - if (HasValue()) + if (Valid()) return storage; return std::nullopt; } diff --git a/src/messages/text_document_definition.cc b/src/messages/text_document_definition.cc index 35fec5bd..f431e146 100644 --- a/src/messages/text_document_definition.cc +++ b/src/messages/text_document_definition.cc @@ -105,7 +105,8 @@ struct Handler_TextDocumentDefinition if (uses.empty() && on_def) uses.push_back(*on_def); } - AddRange(&out.result, GetLsLocationExs(db, working_files, uses)); + auto locs = GetLsLocationExs(db, working_files, uses); + out.result.insert(out.result.end(), locs.begin(), locs.end()); if (!out.result.empty()) break; } diff --git a/src/method.cc b/src/method.cc index f1e38590..99af41a3 100644 --- a/src/method.cc +++ b/src/method.cc @@ -5,13 +5,3 @@ MethodType kMethodType_Exit = "exit"; MethodType kMethodType_TextDocumentPublishDiagnostics = "textDocument/publishDiagnostics"; MethodType kMethodType_CclsPublishInactiveRegions = "$ccls/publishInactiveRegions"; MethodType kMethodType_CclsPublishSemanticHighlighting = "$ccls/publishSemanticHighlighting"; - -InMessage::~InMessage() = default; - -lsRequestId RequestInMessage::GetRequestId() const { - return id; -} - -lsRequestId NotificationInMessage::GetRequestId() const { - return std::monostate(); -} \ No newline at end of file diff --git a/src/method.h b/src/method.h index 7931673e..a336ed5b 100644 --- a/src/method.h +++ b/src/method.h @@ -15,7 +15,7 @@ extern MethodType kMethodType_CclsPublishSemanticHighlighting; using lsRequestId = std::variant; struct InMessage { - virtual ~InMessage(); + virtual ~InMessage() = default; virtual MethodType GetMethodType() const = 0; virtual lsRequestId GetRequestId() const = 0; @@ -24,10 +24,14 @@ struct InMessage { struct RequestInMessage : public InMessage { // number or string, actually no null lsRequestId id; - lsRequestId GetRequestId() const override; + lsRequestId GetRequestId() const override { + return id; + } }; // NotificationInMessage does not have |id|. struct NotificationInMessage : public InMessage { - lsRequestId GetRequestId() const override; + lsRequestId GetRequestId() const override { + return std::monostate(); + } }; diff --git a/src/position.cc b/src/position.cc index 37c94c6e..abcab312 100644 --- a/src/position.cc +++ b/src/position.cc @@ -1,74 +1,29 @@ #include "position.h" +#include "serializer.h" + +#include +#include #include -Position::Position() : line(-1), column(-1) {} - -Position::Position(int16_t line, int16_t column) : line(line), column(column) {} - -Position::Position(const char* encoded) { - char* p = const_cast(encoded); - line = int16_t(strtol(p, &p, 10)) - 1; +Position Position::FromString(const std::string& encoded) { + char* p = const_cast(encoded.c_str()); + int16_t line = int16_t(strtol(p, &p, 10)) - 1; assert(*p == ':'); p++; - column = int16_t(strtol(p, &p, 10)) - 1; + int16_t column = int16_t(strtol(p, &p, 10)) - 1; + return {line, column}; } std::string Position::ToString() { - // Output looks like this: - // - // 1:2 - // - // 1 => line - // 2 => column - - std::string result; - result += std::to_string(line + 1); - result += ':'; - result += std::to_string(column + 1); - return result; + char buf[99]; + snprintf(buf, sizeof buf, "%d:%d", line + 1, column + 1); + return buf; } -std::string Position::ToPrettyString(const std::string& filename) { - // Output looks like this: - // - // 1:2:3 - // - // 1 => filename - // 2 => line - // 3 => column - - std::string result; - result += filename; - result += ':'; - result += std::to_string(line + 1); - result += ':'; - result += std::to_string(column + 1); - return result; -} - -bool Position::operator==(const Position& that) const { - return line == that.line && column == that.column; -} - -bool Position::operator!=(const Position& that) const { - return !(*this == that); -} - -bool Position::operator<(const Position& that) const { - if (line != that.line) - return line < that.line; - return column < that.column; -} - -Range::Range() {} - -Range::Range(Position position) : Range(position, position) {} - -Range::Range(Position start, Position end) : start(start), end(end) {} - -Range::Range(const char* encoded) { - char* p = const_cast(encoded); +Range Range::FromString(const std::string& encoded) { + Position start, end; + char* p = const_cast(encoded.c_str()); start.line = int16_t(strtol(p, &p, 10)) - 1; assert(*p == ':'); p++; @@ -80,18 +35,14 @@ Range::Range(const char* encoded) { assert(*p == ':'); p++; end.column = int16_t(strtol(p, nullptr, 10)) - 1; + return {start, end}; } bool Range::Contains(int line, int column) const { - if (line == start.line && line == end.line) - return column >= start.column && column < end.column; - if (line == start.line) - return column >= start.column; - if (line == end.line) - return column < end.column; - if (line > start.line && line < end.line) - return true; - return false; + if (line > INT16_MAX) + return false; + Position p{int16_t(line), int16_t(std::min(column, INT16_MAX))}; + return !(p < start) && p < end; } Range Range::RemovePrefix(Position position) const { @@ -99,47 +50,16 @@ Range Range::RemovePrefix(Position position) const { } std::string Range::ToString() { - // Output looks like this: - // - // 1:2-3:4 - // - // 1 => start line - // 2 => start column - // 3 => end line - // 4 => end column - - std::string output; - - output += std::to_string(start.line + 1); - output += ':'; - output += std::to_string(start.column + 1); - output += '-'; - output += std::to_string(end.line + 1); - output += ':'; - output += std::to_string(end.column + 1); - - return output; -} - -bool Range::operator==(const Range& that) const { - return start == that.start && end == that.end; -} - -bool Range::operator!=(const Range& that) const { - return !(*this == that); -} - -bool Range::operator<(const Range& that) const { - if (start != that.start) - return start < that.start; - return end < that.end; + char buf[99]; + snprintf(buf, sizeof buf, "%d:%d-%d:%d", start.line + 1, start.column + 1, + end.line + 1, end.column + 1); + return buf; } // Position void Reflect(Reader& visitor, Position& value) { if (visitor.Format() == SerializeFormat::Json) { - std::string s = visitor.GetString(); - value = Position(s.c_str()); + value = Position::FromString(visitor.GetString()); } else { Reflect(visitor, value.line); Reflect(visitor, value.column); @@ -158,8 +78,7 @@ void Reflect(Writer& visitor, Position& value) { // Range void Reflect(Reader& visitor, Range& value) { if (visitor.Format() == SerializeFormat::Json) { - std::string s = visitor.GetString(); - value = Range(s.c_str()); + value = Range::FromString(visitor.GetString()); } else { Reflect(visitor, value.start.line); Reflect(visitor, value.start.column); diff --git a/src/position.h b/src/position.h index 8d238b55..748bb741 100644 --- a/src/position.h +++ b/src/position.h @@ -1,57 +1,56 @@ #pragma once #include "maybe.h" -#include "serializer.h" #include "utils.h" #include #include struct Position { - int16_t line; - int16_t column; + int16_t line = -1; + int16_t column = -1; - Position(); - Position(int16_t line, int16_t column); - explicit Position(const char* encoded); + static Position FromString(const std::string& encoded); - bool HasValueForMaybe_() const { return line >= 0; } + bool Valid() const { return line >= 0; } std::string ToString(); - std::string ToPrettyString(const std::string& filename); // Compare two Positions and check if they are equal. Ignores the value of // |interesting|. - bool operator==(const Position& that) const; - bool operator!=(const Position& that) const; - bool operator<(const Position& that) const; + bool operator==(const Position& o) const { + return line == o.line && column == o.column; + } + bool operator<(const Position& o) const { + if (line != o.line) + return line < o.line; + return column < o.column; + } }; -static_assert( - sizeof(Position) == 4, - "Investigate, Position should be 32-bits for indexer size reasons"); MAKE_HASHABLE(Position, t.line, t.column); struct Range { Position start; Position end; - Range(); - explicit Range(Position position); - Range(Position start, Position end); - explicit Range(const char* encoded); + static Range FromString(const std::string& encoded); - bool HasValueForMaybe_() const { return start.HasValueForMaybe_(); } + bool Valid() const { return start.Valid(); } bool Contains(int line, int column) const; Range RemovePrefix(Position position) const; std::string ToString(); - bool operator==(const Range& that) const; - bool operator!=(const Range& that) const; - bool operator<(const Range& that) const; + bool operator==(const Range& o) const { + return start == o.start && end == o.end; + } + bool operator<(const Range& o) const { + return !(start == o.start) ? start < o.start : end < o.end; + } }; -MAKE_HASHABLE(Range, t.start, t.end); // Reflection +class Reader; +class Writer; void Reflect(Reader& visitor, Position& value); void Reflect(Writer& visitor, Position& value); void Reflect(Reader& visitor, Range& value); diff --git a/src/query.cc b/src/query.cc index e504619b..8d28f2a0 100644 --- a/src/query.cc +++ b/src/query.cc @@ -11,14 +11,30 @@ #include #include #include +#include #include #include #include // TODO: Make all copy constructors explicit. +// Used by |HANDLE_MERGEABLE| so only |range| is needed. +MAKE_HASHABLE(Range, t.start, t.end); +MAKE_HASHABLE(Use, t.range); + namespace { +template +void AddRange(std::vector* dest, const std::vector& to_add) { + dest->insert(dest->end(), to_add.begin(), to_add.end()); +} + +template +void AddRange(std::vector* dest, std::vector&& to_add) { + dest->insert(dest->end(), std::make_move_iterator(to_add.begin()), + std::make_move_iterator(to_add.end())); +} + template void RemoveRange(std::vector* dest, const std::vector& to_remove) { std::unordered_set to_remove_set(to_remove.begin(), to_remove.end()); @@ -897,7 +913,7 @@ void QueryDatabase::ImportOrUpdate(std::vector&& updates) { void QueryDatabase::UpdateSymbols(Maybe>* symbol_idx, SymbolKind kind, Id idx) { - if (!symbol_idx->HasValue()) { + if (!symbol_idx->Valid()) { *symbol_idx = Id(symbols.size()); symbols.push_back(SymbolIdx{idx, kind}); } @@ -928,255 +944,3 @@ std::string_view QueryDatabase::GetSymbolName(RawId symbol_idx, } return ""; } - -TEST_SUITE("query") { - IndexUpdate GetDelta(IndexFile previous, IndexFile current) { - QueryDatabase db; - IdMap previous_map(&db, previous.id_cache); - IdMap current_map(&db, current.id_cache); - return IndexUpdate::CreateDelta(&previous_map, ¤t_map, &previous, - ¤t); - } - - TEST_CASE("remove defs") { - IndexFile previous("foo.cc", ""); - IndexFile current("foo.cc", ""); - - previous.Resolve(previous.ToTypeId(HashUsr("usr1")))->def.spell = - Use(Range(Position(1, 0)), {}, {}, {}, {}); - previous.Resolve(previous.ToFuncId(HashUsr("usr2")))->def.spell = - Use(Range(Position(2, 0)), {}, {}, {}, {}); - previous.Resolve(previous.ToVarId(HashUsr("usr3")))->def.spell = - Use(Range(Position(3, 0)), {}, {}, {}, {}); - - IndexUpdate update = GetDelta(previous, current); - - REQUIRE(update.types_removed == std::vector{HashUsr("usr1")}); - REQUIRE(update.funcs_removed.size() == 1); - REQUIRE(update.funcs_removed[0].usr == HashUsr("usr2")); - REQUIRE(update.vars_removed.size() == 1); - REQUIRE(update.vars_removed[0].usr == HashUsr("usr3")); - } - - TEST_CASE("do not remove ref-only defs") { - IndexFile previous("foo.cc", ""); - IndexFile current("foo.cc", ""); - - previous.Resolve(previous.ToTypeId(HashUsr("usr1"))) - ->uses.push_back(Use{Range(Position(1, 0)), {}, {}, {}, {}}); - previous.Resolve(previous.ToFuncId(HashUsr("usr2"))) - ->uses.push_back(Use(Range(Position(2, 0)), {}, {}, {}, {})); - previous.Resolve(previous.ToVarId(HashUsr("usr3"))) - ->uses.push_back(Use(Range(Position(3, 0)), {}, {}, {}, {})); - - IndexUpdate update = GetDelta(previous, current); - - REQUIRE(update.types_removed == std::vector{}); - REQUIRE(update.funcs_removed.empty()); - REQUIRE(update.vars_removed.empty()); - } - - TEST_CASE("func callers") { - IndexFile previous("foo.cc", ""); - IndexFile current("foo.cc", ""); - - IndexFunc* pf = previous.Resolve(previous.ToFuncId(HashUsr("usr"))); - IndexFunc* cf = current.Resolve(current.ToFuncId(HashUsr("usr"))); - - pf->uses.push_back(Use(Range(Position(1, 0)), {}, {}, {}, {})); - cf->uses.push_back(Use(Range(Position(2, 0)), {}, {}, {}, {})); - - IndexUpdate update = GetDelta(previous, current); - - REQUIRE(update.funcs_removed.empty()); - REQUIRE(update.funcs_uses.size() == 1); - REQUIRE(update.funcs_uses[0].id == QueryFuncId(0)); - REQUIRE(update.funcs_uses[0].to_remove.size() == 1); - REQUIRE(update.funcs_uses[0].to_remove[0].range == Range(Position(1, 0))); - REQUIRE(update.funcs_uses[0].to_add.size() == 1); - REQUIRE(update.funcs_uses[0].to_add[0].range == Range(Position(2, 0))); - } - - TEST_CASE("type usages") { - IndexFile previous("foo.cc", ""); - IndexFile current("foo.cc", ""); - - IndexType* pt = previous.Resolve(previous.ToTypeId(HashUsr("usr"))); - IndexType* ct = current.Resolve(current.ToTypeId(HashUsr("usr"))); - - pt->uses.push_back(Use(Range(Position(1, 0)), {}, {}, {}, {})); - ct->uses.push_back(Use(Range(Position(2, 0)), {}, {}, {}, {})); - - IndexUpdate update = GetDelta(previous, current); - - REQUIRE(update.types_removed == std::vector{}); - REQUIRE(update.types_def_update.empty()); - REQUIRE(update.types_uses.size() == 1); - REQUIRE(update.types_uses[0].to_remove.size() == 1); - REQUIRE(update.types_uses[0].to_remove[0].range == Range(Position(1, 0))); - REQUIRE(update.types_uses[0].to_add.size() == 1); - REQUIRE(update.types_uses[0].to_add[0].range == Range(Position(2, 0))); - } - - TEST_CASE("apply delta") { - IndexFile previous("foo.cc", ""); - IndexFile current("foo.cc", ""); - - IndexFunc* pf = previous.Resolve(previous.ToFuncId(HashUsr("usr"))); - IndexFunc* cf = current.Resolve(current.ToFuncId(HashUsr("usr"))); - pf->uses.push_back(Use(Range(Position(1, 0)), {}, {}, {}, {})); - pf->uses.push_back(Use(Range(Position(2, 0)), {}, {}, {}, {})); - cf->uses.push_back(Use(Range(Position(4, 0)), {}, {}, {}, {})); - cf->uses.push_back(Use(Range(Position(5, 0)), {}, {}, {}, {})); - - QueryDatabase db; - IdMap previous_map(&db, previous.id_cache); - IdMap current_map(&db, current.id_cache); - REQUIRE(db.funcs.size() == 1); - - IndexUpdate import_update = - IndexUpdate::CreateDelta(nullptr, &previous_map, nullptr, &previous); - IndexUpdate delta_update = IndexUpdate::CreateDelta( - &previous_map, ¤t_map, &previous, ¤t); - - db.ApplyIndexUpdate(&import_update); - REQUIRE(db.funcs[0].uses.size() == 2); - REQUIRE(db.funcs[0].uses[0].range == Range(Position(1, 0))); - REQUIRE(db.funcs[0].uses[1].range == Range(Position(2, 0))); - - db.ApplyIndexUpdate(&delta_update); - REQUIRE(db.funcs[0].uses.size() == 2); - REQUIRE(db.funcs[0].uses[0].range == Range(Position(4, 0))); - REQUIRE(db.funcs[0].uses[1].range == Range(Position(5, 0))); - } - - TEST_CASE("Remove variable with usage") { - auto load_index_from_json = [](const char* json) { - return Deserialize(SerializeFormat::Json, "foo.cc", json, "", - std::nullopt); - }; - - auto previous = load_index_from_json(R"RAW( -{ - "types": [ - { - "id": 0, - "usr": 17, - "detailed_name": "", - "short_name_offset": 0, - "short_name_size": 0, - "kind": 0, - "hover": "", - "comments": "", - "parents": [], - "derived": [], - "types": [], - "funcs": [], - "vars": [], - "instances": [ - 0 - ], - "uses": [] - } - ], - "funcs": [ - { - "id": 0, - "usr": 4259594751088586730, - "detailed_name": "void foo()", - "short_name_offset": 5, - "short_name_size": 3, - "kind": 12, - "storage": 1, - "hover": "", - "comments": "", - "declarations": [], - "spell": "1:6-1:9|-1|1|2", - "extent": "1:1-4:2|-1|1|0", - "base": [], - "derived": [], - "locals": [], - "uses": [], - "callees": [] - } - ], - "vars": [ - { - "id": 0, - "usr": 16837348799350457167, - "detailed_name": "int a", - "short_name_offset": 4, - "short_name_size": 1, - "hover": "", - "comments": "", - "declarations": [], - "spell": "2:7-2:8|0|3|2", - "extent": "2:3-2:8|0|3|2", - "type": 0, - "uses": [ - "3:3-3:4|0|3|4" - ], - "kind": 13, - "storage": 1 - } - ] -} - )RAW"); - - auto current = load_index_from_json(R"RAW( -{ - "types": [], - "funcs": [ - { - "id": 0, - "usr": 4259594751088586730, - "detailed_name": "void foo()", - "short_name_offset": 5, - "short_name_size": 3, - "kind": 12, - "storage": 1, - "hover": "", - "comments": "", - "declarations": [], - "spell": "1:6-1:9|-1|1|2", - "extent": "1:1-5:2|-1|1|0", - "base": [], - "derived": [], - "locals": [], - "uses": [], - "callees": [] - } - ], - "vars": [] -} - )RAW"); - - // Validate previous/current were parsed. - REQUIRE(previous->vars.size() == 1); - REQUIRE(current->vars.size() == 0); - - QueryDatabase db; - - // Apply initial file. - { - IdMap previous_map(&db, previous->id_cache); - IndexUpdate import_update = IndexUpdate::CreateDelta( - nullptr, &previous_map, nullptr, previous.get()); - db.ApplyIndexUpdate(&import_update); - } - - REQUIRE(db.vars.size() == 1); - REQUIRE(db.vars[0].uses.size() == 1); - - // Apply change. - { - IdMap previous_map(&db, previous->id_cache); - IdMap current_map(&db, current->id_cache); - IndexUpdate delta_update = IndexUpdate::CreateDelta( - &previous_map, ¤t_map, previous.get(), current.get()); - db.ApplyIndexUpdate(&delta_update); - } - REQUIRE(db.vars.size() == 1); - REQUIRE(db.vars[0].uses.size() == 0); - } -} diff --git a/src/query_utils.cc b/src/query_utils.cc index bf61ba64..95d33b5a 100644 --- a/src/query_utils.cc +++ b/src/query_utils.cc @@ -47,8 +47,8 @@ Maybe GetDefinitionSpell(QueryDatabase* db, SymbolIdx sym) { Maybe GetDefinitionExtent(QueryDatabase* db, SymbolIdx sym) { // Used to jump to file. if (sym.kind == SymbolKind::File) - return Use(Range(Position(0, 0), Position(0, 0)), sym.id, sym.kind, - Role::None, QueryFileId(sym.id)); + return Use(Range{{0, 0}, {0, 0}}, sym.id, sym.kind, Role::None, + QueryFileId(sym.id)); Maybe ret; EachEntityDef(db, sym, [&](const auto& def) { return !(ret = def.extent); }); return ret; @@ -126,7 +126,7 @@ std::vector GetUsesForAllBases(QueryDatabase* db, QueryFunc& root) { if (!seen.count(func1.usr)) { seen.insert(func1.usr); stack.push_back(&func1); - AddRange(&ret, func1.uses); + ret.insert(ret.end(), func1.uses.begin(), func1.uses.end()); } }); } @@ -147,7 +147,7 @@ std::vector GetUsesForAllDerived(QueryDatabase* db, QueryFunc& root) { if (!seen.count(func1.usr)) { seen.insert(func1.usr); stack.push_back(&func1); - AddRange(&ret, func1.uses); + ret.insert(ret.end(), func1.uses.begin(), func1.uses.end()); } }); } diff --git a/src/serializer.h b/src/serializer.h index 5807a595..4ea92cc7 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -231,7 +231,7 @@ void ReflectMember(Writer& visitor, const char* name, std::optional& value) { // The same as std::optional template void ReflectMember(Writer& visitor, const char* name, Maybe& value) { - if (value.HasValue() || visitor.Format() != SerializeFormat::Json) { + if (value.Valid() || visitor.Format() != SerializeFormat::Json) { visitor.Key(name); Reflect(visitor, value); } diff --git a/src/test.cc b/src/test.cc index a8075815..7155b0bd 100644 --- a/src/test.cc +++ b/src/test.cc @@ -229,16 +229,17 @@ IndexFile* FindDbForPathEnding( bool RunIndexTests(const std::string& filter_path, bool enable_update) { gTestOutputMode = true; + std::string version = ToString(clang_getClangVersion()); // Index tests change based on the version of clang used. static const char kRequiredClangVersion[] = "clang version 6.0.0 (tags/RELEASE_600/final)"; - if (GetClangVersion() != kRequiredClangVersion && - GetClangVersion().find("trunk") == std::string::npos) { + if (version != kRequiredClangVersion && + version.find("trunk") == std::string::npos) { fprintf(stderr, "Index tests must be run using clang version %s, ccls is running " "with %s\n", - kRequiredClangVersion, GetClangVersion().c_str()); + kRequiredClangVersion, version.c_str()); return false; } diff --git a/src/utils.h b/src/utils.h index 82755e71..6b117d05 100644 --- a/src/utils.h +++ b/src/utils.h @@ -65,17 +65,6 @@ std::optional ReadContent(const std::string& filename); void WriteToFile(const std::string& filename, const std::string& content); -template -void AddRange(std::vector* dest, const std::vector& to_add) { - dest->insert(dest->end(), to_add.begin(), to_add.end()); -} - -template -void AddRange(std::vector* dest, std::vector&& to_add) { - dest->insert(dest->end(), std::make_move_iterator(to_add.begin()), - std::make_move_iterator(to_add.end())); -} - // http://stackoverflow.com/a/38140932 // // struct SomeHashKey {