
Additionally, add sentinel values <Enum>::First_ and <Enum>::Last_ to each one of those enums. This will allow using `enum_seq_inclusive` to generate the list of enum-typed values of any generated scoped (non-bitmask) enum.
163 lines
4.9 KiB
C++
163 lines
4.9 KiB
C++
//===- llvm/unittests/Frontend/OpenMPDirectiveNameParserTest.cpp ----------===//
|
|
//
|
|
// 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/ADT/Sequence.h"
|
|
#include "llvm/ADT/SmallVector.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Frontend/OpenMP/DirectiveNameParser.h"
|
|
#include "llvm/Frontend/OpenMP/OMP.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
#include <cctype>
|
|
#include <sstream>
|
|
#include <string>
|
|
#include <tuple>
|
|
#include <vector>
|
|
|
|
using namespace llvm;
|
|
|
|
static const omp::DirectiveNameParser &getParser() {
|
|
static omp::DirectiveNameParser Parser(omp::SourceLanguage::C |
|
|
omp::SourceLanguage::Fortran);
|
|
return Parser;
|
|
}
|
|
|
|
static std::vector<std::string> tokenize(StringRef S) {
|
|
std::vector<std::string> Tokens;
|
|
|
|
using TokenIterator = std::istream_iterator<std::string>;
|
|
std::string Copy = S.str();
|
|
std::istringstream Stream(Copy);
|
|
|
|
for (auto I = TokenIterator(Stream), E = TokenIterator(); I != E; ++I)
|
|
Tokens.push_back(*I);
|
|
return Tokens;
|
|
}
|
|
|
|
static std::string &prepareParamName(std::string &Name) {
|
|
for (size_t I = 0, E = Name.size(); I != E; ++I) {
|
|
// The parameter name must only have alphanumeric characters.
|
|
if (!isalnum(Name[I]))
|
|
Name[I] = 'X';
|
|
}
|
|
return Name;
|
|
}
|
|
|
|
// Test tokenizing.
|
|
|
|
class Tokenize : public testing::TestWithParam<omp::Directive> {};
|
|
|
|
static bool isEqual(const SmallVector<StringRef> &A,
|
|
const std::vector<std::string> &B) {
|
|
if (A.size() != B.size())
|
|
return false;
|
|
|
|
for (size_t I = 0, E = A.size(); I != E; ++I) {
|
|
if (A[I] != StringRef(B[I]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
TEST_P(Tokenize, T) {
|
|
omp::Directive DirId = GetParam();
|
|
StringRef Name = omp::getOpenMPDirectiveName(DirId, omp::FallbackVersion);
|
|
|
|
SmallVector<StringRef> tokens1 = omp::DirectiveNameParser::tokenize(Name);
|
|
std::vector<std::string> tokens2 = tokenize(Name);
|
|
ASSERT_TRUE(isEqual(tokens1, tokens2));
|
|
}
|
|
|
|
static std::string
|
|
getParamName1(const testing::TestParamInfo<Tokenize::ParamType> &Info) {
|
|
omp::Directive DirId = Info.param;
|
|
std::string Name =
|
|
omp::getOpenMPDirectiveName(DirId, omp::FallbackVersion).str();
|
|
return prepareParamName(Name);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DirectiveNameParserTest, Tokenize,
|
|
testing::ValuesIn(llvm::enum_seq_inclusive(
|
|
omp::Directive::First_, omp::Directive::Last_)),
|
|
getParamName1);
|
|
|
|
// Test parsing of valid names.
|
|
|
|
using ValueType = std::tuple<omp::Directive, unsigned>;
|
|
|
|
class ParseValid : public testing::TestWithParam<ValueType> {};
|
|
|
|
TEST_P(ParseValid, T) {
|
|
auto [DirId, Version] = GetParam();
|
|
if (DirId == omp::Directive::OMPD_unknown)
|
|
return;
|
|
|
|
std::string Name = omp::getOpenMPDirectiveName(DirId, Version).str();
|
|
|
|
// Tokenize and parse
|
|
auto &Parser = getParser();
|
|
auto *State = Parser.initial();
|
|
ASSERT_TRUE(State != nullptr);
|
|
|
|
std::vector<std::string> Tokens = tokenize(Name);
|
|
for (auto &Tok : Tokens) {
|
|
State = Parser.consume(State, Tok);
|
|
ASSERT_TRUE(State != nullptr);
|
|
}
|
|
|
|
ASSERT_EQ(State->Value, DirId);
|
|
}
|
|
|
|
static std::string
|
|
getParamName2(const testing::TestParamInfo<ParseValid::ParamType> &Info) {
|
|
auto [DirId, Version] = Info.param;
|
|
std::string Name = omp::getOpenMPDirectiveName(DirId, Version).str() + "v" +
|
|
std::to_string(Version);
|
|
return prepareParamName(Name);
|
|
}
|
|
|
|
INSTANTIATE_TEST_SUITE_P(
|
|
DirectiveNameParserTest, ParseValid,
|
|
testing::Combine(testing::ValuesIn(llvm::enum_seq_inclusive(
|
|
omp::Directive::First_, omp::Directive::Last_)),
|
|
testing::ValuesIn(omp::getOpenMPVersions())),
|
|
getParamName2);
|
|
|
|
// Test parsing of invalid names
|
|
|
|
class ParseInvalid : public testing::TestWithParam<std::string> {};
|
|
|
|
TEST_P(ParseInvalid, T) {
|
|
std::string Name = GetParam();
|
|
|
|
auto &Parser = getParser();
|
|
auto *State = Parser.initial();
|
|
ASSERT_TRUE(State != nullptr);
|
|
|
|
std::vector<std::string> Tokens = tokenize(Name);
|
|
for (auto &Tok : Tokens)
|
|
State = Parser.consume(State, Tok);
|
|
|
|
ASSERT_TRUE(State == nullptr || State->Value == omp::Directive::OMPD_unknown);
|
|
}
|
|
|
|
namespace {
|
|
using namespace std;
|
|
|
|
INSTANTIATE_TEST_SUITE_P(DirectiveNameParserTest, ParseInvalid,
|
|
testing::Values(
|
|
// Names that contain invalid tokens
|
|
"bad"s, "target teams invalid"s,
|
|
"target sections parallel"s,
|
|
"target teams distribute parallel for wrong"s,
|
|
// Valid beginning, but not a complete name
|
|
"begin declare"s,
|
|
// Complete name with extra tokens
|
|
"distribute simd target"s));
|
|
} // namespace
|