mirror of
https://github.com/carbon-language/carbon-lang.git
synced 2026-09-24 21:20:11 +01:00
Most of these were fixed automatically (including things like adding `[[nodiscard]]` and such). A number of others required manual edits. I think all of them were pretty nice improvements. There were a few places where the issues really stem from external constraints and I've disabled the checks: GoogleTest macros or the specific LibFuzzer entry points. The only other places I disabled are the implicit conversions to a private `enum` in the classes wrapping those `enum`s. These implicit conversions are necessarily implicit to serve their only purpose: enabling their use in `switch` statements and `case` labels. When these were highlighted, it showed that one of these was actually converting to an *`int`*. I've switched that to use the private `enum` instead as doing so is important to enable warnings on non-covering `switch` statements over than `enum`. And indeed, there is a `switch` that was was implicitly relying on falling through in this way, so I've added the explicit documentation of the intentional pattern to address that warning. Sorry this is so large, all of this somewhat fell out of enabling the `clang-tidy` checks. If it is too difficult to review as lump, I can work on breaking it apart as needed. Just let me know.
180 lines
5.9 KiB
C++
180 lines
5.9 KiB
C++
// Part of the Carbon Language project, under the Apache License v2.0 with LLVM
|
|
// Exceptions. See /LICENSE for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
|
|
#ifndef LEXER_TOKENIZED_BUFFER_TEST_HELPERS_H_
|
|
#define LEXER_TOKENIZED_BUFFER_TEST_HELPERS_H_
|
|
|
|
#include "gmock/gmock.h"
|
|
#include "lexer/tokenized_buffer.h"
|
|
#include "llvm/ADT/SmallString.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/YAMLParser.h"
|
|
|
|
namespace Carbon {
|
|
|
|
inline void PrintTo(const TokenizedBuffer& buffer, std::ostream* output) {
|
|
std::string message;
|
|
llvm::raw_string_ostream message_stream(message);
|
|
message_stream << "\n";
|
|
buffer.Print(message_stream);
|
|
*output << message_stream.str();
|
|
}
|
|
|
|
namespace Testing {
|
|
|
|
struct ExpectedToken {
|
|
TokenKind kind;
|
|
int line = -1;
|
|
int column = -1;
|
|
int indent_column = -1;
|
|
bool recovery = false;
|
|
llvm::StringRef text = "";
|
|
|
|
friend auto operator<<(std::ostream& output, const ExpectedToken& expected)
|
|
-> std::ostream& {
|
|
output << "\ntoken: { kind: '" << expected.kind.Name().str();
|
|
if (expected.line != -1) {
|
|
output << "', line: " << expected.line;
|
|
}
|
|
if (expected.column != -1) {
|
|
output << ", column " << expected.column;
|
|
}
|
|
if (expected.indent_column != -1) {
|
|
output << ", indent: " << expected.indent_column;
|
|
}
|
|
if (!expected.text.empty()) {
|
|
output << ", spelling: '" << expected.text.str() << "'";
|
|
}
|
|
if (expected.recovery) {
|
|
output << ", recovery: true";
|
|
}
|
|
output << " }";
|
|
return output;
|
|
}
|
|
};
|
|
|
|
// TODO: Consider rewriting this into a `TokenEq` matcher which is used inside
|
|
// `ElementsAre`. If that isn't easily done, potentially worth checking for size
|
|
// mismatches first.
|
|
// NOLINTNEXTLINE: Expands from GoogleTest.
|
|
MATCHER_P(HasTokens, raw_all_expected, "") {
|
|
const TokenizedBuffer& buffer = arg;
|
|
llvm::ArrayRef<ExpectedToken> all_expected = raw_all_expected;
|
|
|
|
bool matches = true;
|
|
auto buffer_it = buffer.Tokens().begin();
|
|
for (const ExpectedToken& expected : all_expected) {
|
|
if (buffer_it == buffer.Tokens().end()) {
|
|
// The size check outside the loop will fail and print useful info.
|
|
break;
|
|
}
|
|
|
|
int index = buffer_it - buffer.Tokens().begin();
|
|
auto token = *buffer_it++;
|
|
|
|
TokenKind actual_kind = buffer.GetKind(token);
|
|
if (actual_kind != expected.kind) {
|
|
*result_listener << "\nToken " << index << " is a "
|
|
<< actual_kind.Name().str() << ", expected a "
|
|
<< expected.kind.Name().str() << ".";
|
|
matches = false;
|
|
}
|
|
|
|
int actual_line = buffer.GetLineNumber(token);
|
|
if (expected.line != -1 && actual_line != expected.line) {
|
|
*result_listener << "\nToken " << index << " is at line " << actual_line
|
|
<< ", expected " << expected.line << ".";
|
|
matches = false;
|
|
}
|
|
|
|
int actual_column = buffer.GetColumnNumber(token);
|
|
if (expected.column != -1 && actual_column != expected.column) {
|
|
*result_listener << "\nToken " << index << " is at column "
|
|
<< actual_column << ", expected " << expected.column
|
|
<< ".";
|
|
matches = false;
|
|
}
|
|
|
|
int actual_indent_column =
|
|
buffer.GetIndentColumnNumber(buffer.GetLine(token));
|
|
if (expected.indent_column != -1 &&
|
|
actual_indent_column != expected.indent_column) {
|
|
*result_listener << "\nToken " << index << " has column indent "
|
|
<< actual_indent_column << ", expected "
|
|
<< expected.indent_column << ".";
|
|
matches = false;
|
|
}
|
|
|
|
int actual_recovery = buffer.IsRecoveryToken(token);
|
|
if (expected.recovery != actual_recovery) {
|
|
*result_listener << "\nToken " << index << " is "
|
|
<< (actual_recovery ? "recovery" : "non-recovery")
|
|
<< ", expected "
|
|
<< (expected.recovery ? "recovery" : "non-recovery")
|
|
<< ".";
|
|
matches = false;
|
|
}
|
|
|
|
llvm::StringRef actual_text = buffer.GetTokenText(token);
|
|
if (!expected.text.empty() && actual_text != expected.text) {
|
|
*result_listener << "\nToken " << index << " has spelling `"
|
|
<< actual_text.str() << "`, expected `"
|
|
<< expected.text.str() << "`.";
|
|
matches = false;
|
|
}
|
|
}
|
|
|
|
int actual_size = buffer.Tokens().end() - buffer.Tokens().begin();
|
|
if (static_cast<int>(all_expected.size()) != actual_size) {
|
|
*result_listener << "\nExpected " << all_expected.size()
|
|
<< " tokens but found " << actual_size << ".";
|
|
matches = false;
|
|
}
|
|
return matches;
|
|
}
|
|
|
|
// NOLINTNEXTLINE: Expands from GoogleTest.
|
|
MATCHER_P2(IsKeyValueScalars, key, value, "") {
|
|
auto* kv_node = llvm::dyn_cast<llvm::yaml::KeyValueNode>(arg);
|
|
if (!kv_node) {
|
|
*result_listener << "this is a `" << arg->getType()
|
|
<< "` node, not a `KeyValueNode`.";
|
|
return false;
|
|
}
|
|
|
|
llvm::SmallString<128> storage;
|
|
|
|
auto* key_node = llvm::dyn_cast<llvm::yaml::ScalarNode>(kv_node->getKey());
|
|
if (!key_node) {
|
|
*result_listener << "the key is a `" << arg->getType()
|
|
<< "` node, not a `ScalarNode`.";
|
|
return false;
|
|
}
|
|
if (key != key_node->getValue(storage)) {
|
|
*result_listener << "the key is `" << key_node->getValue(storage).str()
|
|
<< "`, expected `" << key << "`.";
|
|
return false;
|
|
}
|
|
|
|
auto* value_node =
|
|
llvm::dyn_cast<llvm::yaml::ScalarNode>(kv_node->getValue());
|
|
if (!value_node) {
|
|
*result_listener << "the value is a `" << arg->getType()
|
|
<< "` node, not a `ScalarNode`.";
|
|
return false;
|
|
}
|
|
if (value != value_node->getValue(storage)) {
|
|
*result_listener << "the value is `" << value_node->getValue(storage).str()
|
|
<< "`, expected `" << value << "`.";
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
} // namespace Testing
|
|
} // namespace Carbon
|
|
|
|
#endif // LEXER_TOKENIZED_BUFFER_TEST_HELPERS_H_
|