Index: clangd/index/Index.h =================================================================== --- clangd/index/Index.h +++ clangd/index/Index.h @@ -17,6 +17,7 @@ #include "llvm/ADT/Hashing.h" #include "llvm/ADT/Optional.h" #include "llvm/ADT/StringExtras.h" +#include "llvm/Support/StringSaver.h" #include #include @@ -257,6 +258,8 @@ // The frozen SymbolSlab will use less memory. class Builder { public: + Builder() : UniqueStrings(Arena) {} + // Adds a symbol, overwriting any existing one with the same ID. // This is a deep copy: underlying strings will be owned by the slab. void insert(const Symbol &S); @@ -273,7 +276,7 @@ private: llvm::BumpPtrAllocator Arena; // Intern table for strings. Contents are on the arena. - llvm::DenseSet Strings; + llvm::UniqueStringSaver UniqueStrings; std::vector Symbols; // Values are indices into Symbols vector. llvm::DenseMap SymbolIndex; Index: clangd/index/Index.cpp =================================================================== --- clangd/index/Index.cpp +++ clangd/index/Index.cpp @@ -77,16 +77,10 @@ } // Copy the underlying data of the symbol into the owned arena. -static void own(Symbol &S, DenseSet &Strings, +static void own(Symbol &S, llvm::UniqueStringSaver &Strings, BumpPtrAllocator &Arena) { // Intern replaces V with a reference to the same string owned by the arena. - auto Intern = [&](StringRef &V) { - auto R = Strings.insert(V); - if (R.second) { // New entry added to the table, copy the string. - *R.first = V.copy(Arena); - } - V = *R.first; - }; + auto Intern = [&](StringRef &V) { V = Strings.save(V); }; // We need to copy every StringRef field onto the arena. Intern(S.Name); @@ -114,10 +108,10 @@ auto R = SymbolIndex.try_emplace(S.ID, Symbols.size()); if (R.second) { Symbols.push_back(S); - own(Symbols.back(), Strings, Arena); + own(Symbols.back(), UniqueStrings, Arena); } else { auto &Copy = Symbols[R.first->second] = S; - own(Copy, Strings, Arena); + own(Copy, UniqueStrings, Arena); } } @@ -128,7 +122,7 @@ [](const Symbol &L, const Symbol &R) { return L.ID < R.ID; }); // We may have unused strings from overwritten symbols. Build a new arena. BumpPtrAllocator NewArena; - DenseSet Strings; + llvm::UniqueStringSaver Strings(NewArena); for (auto &S : Symbols) own(S, Strings, NewArena); return SymbolSlab(std::move(NewArena), std::move(Symbols)); Index: docs/clang-tidy/checks/abseil-duration-division.rst =================================================================== --- /dev/null +++ docs/clang-tidy/checks/abseil-duration-division.rst @@ -0,0 +1,36 @@ +.. title:: clang-tidy - abseil-duration-division + +abseil-duration-division +======================== + +``absl::Duration`` arithmetic works like it does with integers. That means that +division of two ``absl::Duration`` objects returns an ``int64`` with any fractional +component truncated toward 0. See `this link `_ for more information on arithmetic with ``absl::Duration``. + +For example: + +.. code-block:: c++ + + absl::Duration d = absl::Seconds(3.5); + int64 sec1 = d / absl::Seconds(1); // Truncates toward 0. + int64 sec2 = absl::ToInt64Seconds(d); // Equivalent to division. + assert(sec1 == 3 && sec2 == 3); + + double dsec = d / absl::Seconds(1); // WRONG: Still truncates toward 0. + assert(dsec == 3.0); + +If you want floating-point division, you should use either the +``absl::FDivDuration()`` function, or one of the unit conversion functions such +as ``absl::ToDoubleSeconds()``. For example: + +.. code-block:: c++ + + absl::Duration d = absl::Seconds(3.5); + double dsec1 = absl::FDivDuration(d, absl::Seconds(1)); // GOOD: No truncation. + double dsec2 = absl::ToDoubleSeconds(d); // GOOD: No truncation. + assert(dsec1 == 3.5 && dsec2 == 3.5); + + +This check looks for uses of ``absl::Duration`` division that is done in a +floating-point context, and recommends the use of a function that returns a +floating-point value.