blob: 05833736f3113dc41ccaaf68aa6b9a6af9fd0cb5 [file] [log] [blame]
//===-- PopulateSwitchTest.cpp ----------------------------------*- 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 "TestTU.h"
#include "TweakTesting.h"
#include "gmock/gmock-matchers.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
namespace clang {
namespace clangd {
namespace {
TWEAK_TEST(PopulateSwitch);
TEST_F(PopulateSwitchTest, Test) {
struct Case {
CodeContext Context;
llvm::StringRef TestSource;
llvm::StringRef ExpectedSource;
llvm::StringRef FileName = "TestTU.cpp";
};
Case Cases[]{
{
// No enumerators
Function,
R""(enum Enum {}; ^switch ((Enum)0) {})"",
"unavailable",
},
{
// All enumerators already in switch (unscoped)
Function,
R""(enum Enum {A,B}; ^switch (A) {case A:break;case B:break;})"",
"unavailable",
},
{
// All enumerators already in switch (scoped)
Function,
R""(
enum class Enum {A,B};
^switch (Enum::A) {case Enum::A:break;case Enum::B:break;}
)"",
"unavailable",
},
{
// Default case in switch
Function,
R""(
enum class Enum {A,B};
^switch (Enum::A) {default:break;}
)"",
"unavailable",
},
{
// GNU range in switch
Function,
R""(
enum class Enum {A,B};
^switch (Enum::A) {case Enum::A ... Enum::B:break;}
)"",
"unavailable",
},
{
// Value dependent case expression
File,
R""(
enum class Enum {A,B};
template<Enum Value>
void function() {
^switch (Enum::A) {case Value:break;}
}
)"",
"unavailable",
},
{
// Body not CompoundStmt
Function,
R""(enum Enum {A}; ^switch (A);)"",
"unavailable",
},
{
// Selection on switch token
Function,
R""(enum Enum {A}; ^switch (A) {})"",
R""(enum Enum {A}; switch (A) {case A:break;})"",
},
{
// Selection on switch condition
Function,
R""(enum Enum {A}; switch (^A) {})"",
R""(enum Enum {A}; switch (A) {case A:break;})"",
},
{
// Selection of whole switch condition
Function,
R""(enum Enum {A}; switch ([[A]]) {})"",
R""(enum Enum {A}; switch (A) {case A:break;})"",
},
{
// Selection in switch body
Function,
R""(enum Enum {A}; switch (A) {^})"",
R""(enum Enum {A}; switch (A) {case A:break;})"",
},
{
// Scoped enumeration
Function,
R""(enum class Enum {A}; ^switch (Enum::A) {})"",
R""(enum class Enum {A}; switch (Enum::A) {case Enum::A:break;})"",
},
{
// Scoped enumeration with multiple enumerators
Function,
R""(
enum class Enum {A,B};
^switch (Enum::A) {}
)"",
R""(
enum class Enum {A,B};
switch (Enum::A) {case Enum::A:case Enum::B:break;}
)"",
},
{
// Only filling in missing enumerators (unscoped)
Function,
R""(
enum Enum {A,B,C};
^switch (A) {case B:break;}
)"",
R""(
enum Enum {A,B,C};
switch (A) {case B:break;case A:case C:break;}
)"",
},
{
// Only filling in missing enumerators,
// even when using integer literals
Function,
R""(
enum Enum {A,B=1,C};
^switch (A) {case 1:break;}
)"",
R""(
enum Enum {A,B=1,C};
switch (A) {case 1:break;case A:case C:break;}
)"",
},
{
// Only filling in missing enumerators (scoped)
Function,
R""(
enum class Enum {A,B,C};
^switch (Enum::A)
{case Enum::B:break;}
)"",
R""(
enum class Enum {A,B,C};
switch (Enum::A)
{case Enum::B:break;case Enum::A:case Enum::C:break;}
)"",
},
{
// Scoped enumerations in namespace
File,
R""(
namespace ns { enum class Enum {A}; }
void function() { ^switch (ns::Enum::A) {} }
)"",
R""(
namespace ns { enum class Enum {A}; }
void function() { switch (ns::Enum::A) {case ns::Enum::A:break;} }
)"",
},
{
// Unscoped enumerations in namespace
File,
R""(
namespace ns { enum Enum {A}; }
void function() { ^switch (ns::A) {} }
)"",
R""(
namespace ns { enum Enum {A}; }
void function() { switch (ns::A) {case ns::A:break;} }
)"",
},
{
// Duplicated constant names
Function,
R""(enum Enum {A,B,b=B}; ^switch (A) {})"",
R""(enum Enum {A,B,b=B}; switch (A) {case A:case B:break;})"",
},
{
// Duplicated constant names all in switch
Function,
R""(enum Enum {A,B,b=B}; ^switch (A) {case A:case B:break;})"",
"unavailable",
},
{
// Enum is dependent type
File,
R""(template<typename T> void f() {enum Enum {A}; ^switch (A) {}})"",
"unavailable",
},
{// C: Only filling in missing enumerators
Function,
R""(
enum CEnum {A,B,C};
enum CEnum val = A;
^switch (val) {case B:break;}
)"",
R""(
enum CEnum {A,B,C};
enum CEnum val = A;
switch (val) {case B:break;case A:case C:break;}
)"",
"TestTU.c"},
{// C: Only filling in missing enumerators w/ typedefs
Function,
R""(
typedef unsigned long UInteger;
enum ControlState : UInteger;
typedef enum ControlState ControlState;
enum ControlState : UInteger {A,B,C};
ControlState controlState = A;
switch (^controlState) {case A:break;}
)"",
R""(
typedef unsigned long UInteger;
enum ControlState : UInteger;
typedef enum ControlState ControlState;
enum ControlState : UInteger {A,B,C};
ControlState controlState = A;
switch (controlState) {case A:break;case B:case C:break;}
)"",
"TestTU.c"},
};
for (const auto &Case : Cases) {
Context = Case.Context;
FileName = Case.FileName;
EXPECT_EQ(apply(Case.TestSource), Case.ExpectedSource);
}
}
} // namespace
} // namespace clangd
} // namespace clang