| //===-- 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 |