diff options
Diffstat (limited to 'clang-tools-extra/unittests/clangd/Annotations.cpp')
-rw-r--r-- | clang-tools-extra/unittests/clangd/Annotations.cpp | 87 |
1 files changed, 87 insertions, 0 deletions
diff --git a/clang-tools-extra/unittests/clangd/Annotations.cpp b/clang-tools-extra/unittests/clangd/Annotations.cpp new file mode 100644 index 00000000000..69532214eb5 --- /dev/null +++ b/clang-tools-extra/unittests/clangd/Annotations.cpp @@ -0,0 +1,87 @@ +//===--- Annotations.cpp - Annotated source code for unit tests -*- C++-*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===---------------------------------------------------------------------===// +#include "Annotations.h" +#include "SourceCode.h" + +namespace clang { +namespace clangd { +using namespace llvm; + +// Crash if the assertion fails, printing the message and testcase. +// More elegant error handling isn't needed for unit tests. +static void require(bool Assertion, const char *Msg, llvm::StringRef Code) { + if (!Assertion) { + llvm::errs() << "Annotated testcase: " << Msg << "\n" << Code << "\n"; + llvm_unreachable("Annotated testcase assertion failed!"); + } +} + +Annotations::Annotations(StringRef Text) { + auto Here = [this] { return offsetToPosition(Code, Code.size()); }; + auto Require = [this, Text](bool Assertion, const char *Msg) { + require(Assertion, Msg, Text); + }; + Optional<StringRef> Name; + SmallVector<std::pair<StringRef, Position>, 8> OpenRanges; + + Code.reserve(Text.size()); + while (!Text.empty()) { + if (Text.consume_front("^")) { + Points[Name.getValueOr("")].push_back(Here()); + Name = None; + continue; + } + if (Text.consume_front("[[")) { + OpenRanges.emplace_back(Name.getValueOr(""), Here()); + Name = None; + continue; + } + Require(!Name, "$name should be followed by ^ or [["); + if (Text.consume_front("]]")) { + Require(!OpenRanges.empty(), "unmatched ]]"); + Ranges[OpenRanges.back().first].push_back( + {OpenRanges.back().second, Here()}); + OpenRanges.pop_back(); + continue; + } + if (Text.consume_front("$")) { + Name = Text.take_while(llvm::isAlnum); + Text = Text.drop_front(Name->size()); + continue; + } + Code.push_back(Text.front()); + Text = Text.drop_front(); + } + Require(!Name, "unterminated $name"); + Require(OpenRanges.empty(), "unmatched [["); +} + +Position Annotations::point(llvm::StringRef Name) const { + auto I = Points.find(Name); + require(I != Points.end() && I->getValue().size() == 1, + "expected exactly one point", Code); + return I->getValue()[0]; +} +std::vector<Position> Annotations::points(llvm::StringRef Name) const { + auto P = Points.lookup(Name); + return {P.begin(), P.end()}; +} +Range Annotations::range(llvm::StringRef Name) const { + auto I = Ranges.find(Name); + require(I != Ranges.end() && I->getValue().size() == 1, + "expected exactly one range", Code); + return I->getValue()[0]; +} +std::vector<Range> Annotations::ranges(llvm::StringRef Name) const { + auto R = Ranges.lookup(Name); + return {R.begin(), R.end()}; +} + +} // namespace clangd +} // namespace clang |