Location L;
L.uri = URIForFile((*Path));
Position Start, End;
- Start.line = CD.Start.Line;
- Start.character = CD.Start.Column;
- End.line = CD.End.Line;
- End.character = CD.End.Column;
+ Start.line = CD.Start.line();
+ Start.character = CD.Start.column();
+ End.line = CD.End.line();
+ End.character = CD.End.column();
L.range = {Start, End};
SymbolKind SK = indexSymbolKindToSymbolKind(Sym.SymInfo.Kind);
std::string Scope = Sym.Scope;
}
Location LSPLoc;
LSPLoc.uri = URIForFile(*Path);
- LSPLoc.range.start.line = Loc.Start.Line;
- LSPLoc.range.start.character = Loc.Start.Column;
- LSPLoc.range.end.line = Loc.End.Line;
- LSPLoc.range.end.character = Loc.End.Column;
+ LSPLoc.range.start.line = Loc.Start.line();
+ LSPLoc.range.start.character = Loc.Start.column();
+ LSPLoc.range.end.line = Loc.End.line();
+ LSPLoc.range.end.character = Loc.End.column();
return LSPLoc;
}
//===----------------------------------------------------------------------===//
#include "Index.h"
+#include "Logger.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
namespace clangd {
using namespace llvm;
+constexpr uint32_t SymbolLocation::Position::MaxLine;
+constexpr uint32_t SymbolLocation::Position::MaxColumn;
+void SymbolLocation::Position::setLine(uint32_t L) {
+ if (L > MaxLine) {
+ log("Set an overflowed Line {0}", L);
+ Line = MaxLine;
+ return;
+ }
+ Line = L;
+}
+void SymbolLocation::Position::setColumn(uint32_t Col) {
+ if (Col > MaxColumn) {
+ log("Set an overflowed Column {0}", Col);
+ Column = MaxColumn;
+ return;
+ }
+ Column = Col;
+}
+
raw_ostream &operator<<(raw_ostream &OS, const SymbolLocation &L) {
if (!L)
return OS << "(none)";
- return OS << L.FileURI << "[" << L.Start.Line << ":" << L.Start.Column << "-"
- << L.End.Line << ":" << L.End.Column << ")";
+ return OS << L.FileURI << "[" << L.Start.line() << ":" << L.Start.column()
+ << "-" << L.End.line() << ":" << L.End.column() << ")";
}
SymbolID::SymbolID(StringRef USR)
struct SymbolLocation {
// Specify a position (Line, Column) of symbol. Using Line/Column allows us to
// build LSP responses without reading the file content.
+ //
+ // Position is encoded into 32 bits to save space.
+ // If Line/Column overflow, the value will be their maximum value.
struct Position {
- uint32_t Line = 0; // 0-based
+ void setLine(uint32_t Line);
+ uint32_t line() const { return Line; }
+ void setColumn(uint32_t Column);
+ uint32_t column() const { return Column; }
+
+ static constexpr uint32_t MaxLine = (1 << 20) - 1;
+ static constexpr uint32_t MaxColumn = (1 << 12) - 1;
+
+ // Clients should use getters and setters to access these members.
+ // FIXME: hide these members.
+ uint32_t Line : 20; // 0-based
// Using UTF-16 code units.
- uint32_t Column = 0; // 0-based
+ uint32_t Column : 12; // 0-based
};
// The URI of the source file where a symbol occurs.
};
inline bool operator==(const SymbolLocation::Position &L,
const SymbolLocation::Position &R) {
- return std::tie(L.Line, L.Column) == std::tie(R.Line, R.Column);
+ return std::make_tuple(L.line(), L.column()) ==
+ std::make_tuple(R.line(), R.column());
}
inline bool operator<(const SymbolLocation::Position &L,
const SymbolLocation::Position &R) {
- return std::tie(L.Line, L.Column) < std::tie(R.Line, R.Column);
+ return std::make_tuple(L.line(), L.column()) <
+ std::make_tuple(R.line(), R.column());
}
inline bool operator==(const SymbolLocation &L, const SymbolLocation &R) {
return std::tie(L.FileURI, L.Start, L.End) ==
raw_ostream &OS) {
writeVar(Strings.index(Loc.FileURI), OS);
for (const auto &Endpoint : {Loc.Start, Loc.End}) {
- writeVar(Endpoint.Line, OS);
- writeVar(Endpoint.Column, OS);
+ writeVar(Endpoint.line(), OS);
+ writeVar(Endpoint.column(), OS);
}
}
SymbolLocation Loc;
Loc.FileURI = Data.consumeString(Strings);
for (auto *Endpoint : {&Loc.Start, &Loc.End}) {
- Endpoint->Line = Data.consumeVar();
- Endpoint->Column = Data.consumeVar();
+ Endpoint->setLine(Data.consumeVar());
+ Endpoint->setColumn(Data.consumeVar());
}
return Loc;
}
auto CreatePosition = [&SM](SourceLocation Loc) {
auto LSPLoc = sourceLocToPosition(SM, Loc);
SymbolLocation::Position Pos;
- Pos.Line = LSPLoc.line;
- Pos.Column = LSPLoc.character;
+ Pos.setLine(LSPLoc.line);
+ Pos.setColumn(LSPLoc.character);
return Pos;
};
#include "dex/Dex.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Errc.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/YAMLTraits.h"
llvm::Optional<clang::clangd::Symbol> Symbol;
llvm::Optional<RefBundle> Refs;
};
+// A class helps YAML to serialize the 32-bit encoded position (Line&Column),
+// as YAMLIO can't directly map bitfields.
+struct YPosition {
+ uint32_t Line;
+ uint32_t Column;
+};
+
} // namespace
namespace llvm {
namespace yaml {
uint8_t Origin = 0;
};
-template <> struct MappingTraits<SymbolLocation::Position> {
- static void mapping(IO &IO, SymbolLocation::Position &Value) {
+template <> struct MappingTraits<YPosition> {
+ static void mapping(IO &IO, YPosition &Value) {
IO.mapRequired("Line", Value.Line);
IO.mapRequired("Column", Value.Column);
}
};
+struct NormalizedPosition {
+ using Position = clang::clangd::SymbolLocation::Position;
+ NormalizedPosition(IO &) {}
+ NormalizedPosition(IO &, const Position &Pos) {
+ P.Line = Pos.line();
+ P.Column = Pos.column();
+ }
+
+ Position denormalize(IO &) {
+ Position Pos;
+ Pos.setLine(P.Line);
+ Pos.setColumn(P.Column);
+ return Pos;
+ }
+ YPosition P;
+};
+
template <> struct MappingTraits<SymbolLocation> {
static void mapping(IO &IO, SymbolLocation &Value) {
IO.mapRequired("FileURI", Value.FileURI);
- IO.mapRequired("Start", Value.Start);
- IO.mapRequired("End", Value.End);
+ MappingNormalization<NormalizedPosition, SymbolLocation::Position> NStart(
+ IO, Value.Start);
+ IO.mapRequired("Start", NStart->P);
+ MappingNormalization<NormalizedPosition, SymbolLocation::Position> NEnd(
+ IO, Value.End);
+ IO.mapRequired("End", NEnd->P);
}
};
using testing::UnorderedElementsAre;
MATCHER_P(RefRange, Range, "") {
- return std::tie(arg.Location.Start.Line, arg.Location.Start.Column,
- arg.Location.End.Line, arg.Location.End.Column) ==
- std::tie(Range.start.line, Range.start.character, Range.end.line,
- Range.end.character);
+ return std::make_tuple(arg.Location.Start.line(), arg.Location.Start.column(),
+ arg.Location.End.line(), arg.Location.End.column()) ==
+ std::make_tuple(Range.start.line, Range.start.character,
+ Range.end.line, Range.end.character);
}
MATCHER_P(FileURI, F, "") { return arg.Location.FileURI == F; }
MATCHER_P(DeclURI, U, "") { return arg.CanonicalDeclaration.FileURI == U; }
MATCHER_P(Named, N, "") { return arg.Name == N; }
MATCHER_P(RefRange, Range, "") {
- return std::tie(arg.Location.Start.Line, arg.Location.Start.Column,
- arg.Location.End.Line, arg.Location.End.Column) ==
- std::tie(Range.start.line, Range.start.character, Range.end.line,
- Range.end.character);
+ return std::make_tuple(arg.Location.Start.line(), arg.Location.Start.column(),
+ arg.Location.End.line(), arg.Location.End.column()) ==
+ std::make_tuple(Range.start.line, Range.start.character,
+ Range.end.line, Range.end.character);
}
MATCHER_P(FileURI, F, "") { return arg.Location.FileURI == F; }
+TEST(SymbolLocation, Position) {
+ using Position = SymbolLocation::Position;
+ Position Pos;
+
+ Pos.setLine(1);
+ EXPECT_EQ(1u, Pos.line());
+ Pos.setColumn(2);
+ EXPECT_EQ(2u, Pos.column());
+
+ Pos.setLine(Position::MaxLine + 1); // overflow
+ EXPECT_EQ(Pos.line(), Position::MaxLine);
+ Pos.setColumn(Position::MaxColumn + 1); // overflow
+ EXPECT_EQ(Pos.column(), Position::MaxColumn);
+}
+
TEST(SymbolSlab, FindAndIterate) {
SymbolSlab::Builder B;
B.insert(symbol("Z"));
return (arg.IncludeHeader == IncludeHeader) && (arg.References == References);
}
MATCHER_P(DeclRange, Pos, "") {
- return std::tie(arg.CanonicalDeclaration.Start.Line,
- arg.CanonicalDeclaration.Start.Column,
- arg.CanonicalDeclaration.End.Line,
- arg.CanonicalDeclaration.End.Column) ==
- std::tie(Pos.start.line, Pos.start.character, Pos.end.line,
- Pos.end.character);
+ return std::make_tuple(arg.CanonicalDeclaration.Start.line(),
+ arg.CanonicalDeclaration.Start.column(),
+ arg.CanonicalDeclaration.End.line(),
+ arg.CanonicalDeclaration.End.column()) ==
+ std::make_tuple(Pos.start.line, Pos.start.character, Pos.end.line,
+ Pos.end.character);
}
MATCHER_P(DefRange, Pos, "") {
- return std::tie(arg.Definition.Start.Line,
- arg.Definition.Start.Column, arg.Definition.End.Line,
- arg.Definition.End.Column) ==
- std::tie(Pos.start.line, Pos.start.character, Pos.end.line,
- Pos.end.character);
+ return std::make_tuple(
+ arg.Definition.Start.line(), arg.Definition.Start.column(),
+ arg.Definition.End.line(), arg.Definition.End.column()) ==
+ std::make_tuple(Pos.start.line, Pos.start.character, Pos.end.line,
+ Pos.end.character);
}
MATCHER_P(RefCount, R, "") { return int(arg.References) == R; }
MATCHER_P(ForCodeCompletion, IsIndexedForCodeCompletion, "") {
MATCHER(RefRange, "") {
const Ref &Pos = testing::get<0>(arg);
const Range &Range = testing::get<1>(arg);
- return std::tie(Pos.Location.Start.Line, Pos.Location.Start.Column,
- Pos.Location.End.Line, Pos.Location.End.Column) ==
- std::tie(Range.start.line, Range.start.character, Range.end.line,
- Range.end.character);
+ return std::make_tuple(Pos.Location.Start.line(), Pos.Location.Start.column(),
+ Pos.Location.End.line(), Pos.Location.End.column()) ==
+ std::make_tuple(Range.start.line, Range.start.character,
+ Range.end.line, Range.end.character);
}
testing::Matcher<const std::vector<Ref> &>
HaveRanges(const std::vector<Range> Ranges) {