1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 10:42:39 +01:00
llvm-mirror/lib/Testing/Support/Annotations.cpp
Sam McCall efc0ed79a2 [clangd] Implement semanticTokens modifiers
- Infrastructure to support modifiers (protocol etc)
- standard modifiers:
  - declaration (but no definition, yet)
  - deprecated
  - readonly (based on a fairly fuzzy const checking)
  - static (for class members and locals, but *not* file-scope things!)
  - abstract (for C++ classes, and pure-virtual methods)
- nonstandard modifier:
  - deduced (on "auto" whose Kind is Class etc)
    Happy to drop this if it's controversial at all.
- While here, update sample tweak to use our internal names, in
  anticipation of theia TM scopes going away.

This addresses some of the goals of D77702, but leaves some things undone.
Mostly because I think these will want some discussion.
 - no split between dependent type/name.
   (We may want to model this as a modifier, type+dependent vs ???+dependent)
 - no split between primitive/typedef.
   (Is introducing a nonstandard kind is worth this distinction?)
 - no nonstandard local attribute
   This probably makes sense, I'm wondering if we want others and how
   they fit together.

There's one minor regression in explicit template specialization declarations
due to a latent bug in findExplicitReferences, but fixing it after seems OK.

Differential Revision: https://reviews.llvm.org/D77811
2021-02-09 16:31:22 +01:00

101 lines
3.2 KiB
C++

//===--- Annotations.cpp - Annotated source code for unit tests --*- C++-*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "llvm/Testing/Support/Annotations.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/raw_ostream.h"
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(llvm::StringRef Text) {
auto Require = [Text](bool Assertion, const char *Msg) {
require(Assertion, Msg, Text);
};
llvm::Optional<llvm::StringRef> Name;
llvm::SmallVector<std::pair<llvm::StringRef, size_t>, 8> OpenRanges;
Code.reserve(Text.size());
while (!Text.empty()) {
if (Text.consume_front("^")) {
Points[Name.getValueOr("")].push_back(Code.size());
Name = llvm::None;
continue;
}
if (Text.consume_front("[[")) {
OpenRanges.emplace_back(Name.getValueOr(""), Code.size());
Name = llvm::None;
continue;
}
Require(!Name, "$name should be followed by ^ or [[");
if (Text.consume_front("]]")) {
Require(!OpenRanges.empty(), "unmatched ]]");
Range R;
R.Begin = OpenRanges.back().second;
R.End = Code.size();
Ranges[OpenRanges.back().first].push_back(R);
OpenRanges.pop_back();
continue;
}
if (Text.consume_front("$")) {
Name =
Text.take_while([](char C) { return llvm::isAlnum(C) || C == '_'; });
Text = Text.drop_front(Name->size());
continue;
}
Code.push_back(Text.front());
Text = Text.drop_front();
}
Require(!Name, "unterminated $name");
Require(OpenRanges.empty(), "unmatched [[");
}
size_t 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<size_t> Annotations::points(llvm::StringRef Name) const {
auto I = Points.find(Name);
if (I == Points.end())
return {};
return {I->getValue().begin(), I->getValue().end()};
}
Annotations::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<Annotations::Range>
Annotations::ranges(llvm::StringRef Name) const {
auto I = Ranges.find(Name);
if (I == Ranges.end())
return {};
return {I->getValue().begin(), I->getValue().end()};
}
llvm::raw_ostream &llvm::operator<<(llvm::raw_ostream &O,
const llvm::Annotations::Range &R) {
return O << llvm::formatv("[{0}, {1})", R.Begin, R.End);
}