--- /dev/null
+#include "../clang-tidy/utils/FixItHintUtils.h"
+#include "ClangTidyDiagnosticConsumer.h"
+#include "ClangTidyTest.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Tooling/Tooling.h"
+#include "gtest/gtest.h"
+
+namespace clang {
+namespace tidy {
+
+namespace {
+using namespace clang::ast_matchers;
+using namespace utils::fixit;
+
+template <QualifierTarget CT, QualifierPolicy CP>
+class ConstTransform : public ClangTidyCheck {
+public:
+ ConstTransform(StringRef CheckName, ClangTidyContext *Context)
+ : ClangTidyCheck(CheckName, Context) {}
+
+ void registerMatchers(MatchFinder *Finder) override {
+ Finder->addMatcher(varDecl(hasName("target")).bind("var"), this);
+ }
+
+ void check(const MatchFinder::MatchResult &Result) override {
+ const auto *D = Result.Nodes.getNodeAs<VarDecl>("var");
+ using utils::fixit::addQualifierToVarDecl;
+ Optional<FixItHint> Fix = addQualifierToVarDecl(
+ *D, *Result.Context, DeclSpec::TQ::TQ_const, CT, CP);
+ auto Diag = diag(D->getBeginLoc(), "doing const transformation");
+ if (Fix)
+ Diag << *Fix;
+ }
+};
+} // namespace
+
+namespace test {
+using PointeeLTransform =
+ ConstTransform<QualifierTarget::Pointee, QualifierPolicy::Left>;
+using PointeeRTransform =
+ ConstTransform<QualifierTarget::Pointee, QualifierPolicy::Right>;
+
+using ValueLTransform =
+ ConstTransform<QualifierTarget::Value, QualifierPolicy::Left>;
+using ValueRTransform =
+ ConstTransform<QualifierTarget::Value, QualifierPolicy::Right>;
+
+// ----------------------------------------------------------------------------
+// Test Value-like types. Everything with indirection is done later.
+// ----------------------------------------------------------------------------
+
+TEST(Values, Builtin) {
+ StringRef Snippet = "int target = 0;";
+
+ EXPECT_EQ("const int target = 0;", runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("const int target = 0;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+
+ EXPECT_EQ("int const target = 0;", runCheckOnCode<ValueRTransform>(Snippet));
+ EXPECT_EQ("int const target = 0;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Values, TypedefBuiltin) {
+ StringRef T = "typedef int MyInt;";
+ StringRef S = "MyInt target = 0;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const MyInt target = 0;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const MyInt target = 0;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("MyInt const target = 0;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("MyInt const target = 0;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, TypedefBuiltinPointer) {
+ StringRef T = "typedef int* MyInt;";
+ StringRef S = "MyInt target = nullptr;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const MyInt target = nullptr;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const MyInt target = nullptr;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("MyInt const target = nullptr;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("MyInt const target = nullptr;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, UsingBuiltin) {
+ StringRef T = "using MyInt = int;";
+ StringRef S = "MyInt target = 0;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const MyInt target = 0;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const MyInt target = 0;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("MyInt const target = 0;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("MyInt const target = 0;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, UsingBuiltinPointer) {
+ StringRef T = "using MyInt = int*;";
+ StringRef S = "MyInt target = nullptr;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const MyInt target = nullptr;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const MyInt target = nullptr;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("MyInt const target = nullptr;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("MyInt const target = nullptr;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, AutoValue) {
+ StringRef T = "int f() { return 42; }\n";
+ StringRef S = "auto target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const auto target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const auto target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("auto const target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto const target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, AutoPointer) {
+ StringRef T = "int* f() { return nullptr; }\n";
+ StringRef S = "auto target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const auto target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const auto target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("auto const target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto const target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, AutoReference) {
+ StringRef T = "static int global = 42; int& f() { return global; }\n";
+ StringRef S = "auto target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const auto target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const auto target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("auto const target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto const target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, DeclTypeValue) {
+ StringRef T = "int f() { return 42; }\n";
+ StringRef S = "decltype(f()) target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const decltype(f()) target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const decltype(f()) target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("decltype(f()) const target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("decltype(f()) const target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, DeclTypePointer) {
+ // The pointer itself will be changed to 'const'. There is no
+ // way to make the pointee 'const' with this syntax.
+ StringRef T = "int* f() { return nullptr; }\n";
+ StringRef S = "decltype(f()) target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const decltype(f()) target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const decltype(f()) target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("decltype(f()) const target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("decltype(f()) const target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, DeclTypeReference) {
+ // Same as pointer, but the reference itself will be marked 'const'.
+ // This has no effect and will result in a warning afterwards. The
+ // transformation itself is still correct.
+ StringRef T = "static int global = 42; int& f() { return global; }\n";
+ StringRef S = "decltype(f()) target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const decltype(f()) target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const decltype(f()) target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("decltype(f()) const target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("decltype(f()) const target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Values, Parens) {
+ StringRef Snippet = "int ((target)) = 0;";
+
+ EXPECT_EQ("const int ((target)) = 0;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("const int ((target)) = 0;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+
+ EXPECT_EQ("int const ((target)) = 0;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+ EXPECT_EQ("int const ((target)) = 0;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+
+// ----------------------------------------------------------------------------
+// Test builtin-arrays
+// ----------------------------------------------------------------------------
+
+TEST(Arrays, Builtin) {
+ StringRef Snippet = "int target[][1] = {{1}, {2}, {3}};";
+
+ EXPECT_EQ("const int target[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("const int target[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<ValueLTransform>(Snippet));
+
+ EXPECT_EQ("int const target[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+ EXPECT_EQ("int const target[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<ValueRTransform>(Snippet));
+}
+TEST(Arrays, BuiltinParens) {
+ StringRef Snippet = "int ((target))[][1] = {{1}, {2}, {3}};";
+
+ EXPECT_EQ("const int ((target))[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("const int ((target))[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<ValueLTransform>(Snippet));
+
+ EXPECT_EQ("int const ((target))[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+ EXPECT_EQ("int const ((target))[][1] = {{1}, {2}, {3}};",
+ runCheckOnCode<ValueRTransform>(Snippet));
+}
+TEST(Arrays, Pointers) {
+ StringRef Snippet = "int x; int* target[] = {&x, &x, &x};";
+
+ EXPECT_EQ("int x; const int* target[] = {&x, &x, &x};",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("int x; int const* target[] = {&x, &x, &x};",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+
+ EXPECT_EQ("int x; int* const target[] = {&x, &x, &x};",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int x; int* const target[] = {&x, &x, &x};",
+ runCheckOnCode<ValueRTransform>(Snippet));
+}
+TEST(Arrays, PointerPointers) {
+ StringRef Snippet = "int* x = nullptr; int** target[] = {&x, &x, &x};";
+
+ EXPECT_EQ("int* x = nullptr; int* const* target[] = {&x, &x, &x};",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("int* x = nullptr; int** const target[] = {&x, &x, &x};",
+ runCheckOnCode<ValueLTransform>(Snippet));
+
+ EXPECT_EQ("int* x = nullptr; int* const* target[] = {&x, &x, &x};",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+ EXPECT_EQ("int* x = nullptr; int** const target[] = {&x, &x, &x};",
+ runCheckOnCode<ValueRTransform>(Snippet));
+}
+TEST(Arrays, PointersParens) {
+ StringRef Snippet = "int x; int* (target)[] = {&x, &x, &x};";
+
+ EXPECT_EQ("int x; const int* (target)[] = {&x, &x, &x};",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("int x; int const* (target)[] = {&x, &x, &x};",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+
+ EXPECT_EQ("int x; int* const (target)[] = {&x, &x, &x};",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int x; int* const (target)[] = {&x, &x, &x};",
+ runCheckOnCode<ValueRTransform>(Snippet));
+}
+
+// ----------------------------------------------------------------------------
+// Test reference types. This does not include pointers and arrays.
+// ----------------------------------------------------------------------------
+
+TEST(Reference, LValueBuiltin) {
+ StringRef Snippet = "int x = 42; int& target = x;";
+
+ EXPECT_EQ("int x = 42; const int& target = x;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int x = 42; const int& target = x;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+
+ EXPECT_EQ("int x = 42; int const& target = x;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+ EXPECT_EQ("int x = 42; int const& target = x;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Reference, RValueBuiltin) {
+ StringRef Snippet = "int&& target = 42;";
+ EXPECT_EQ("const int&& target = 42;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("const int&& target = 42;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+
+ EXPECT_EQ("int const&& target = 42;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+ EXPECT_EQ("int const&& target = 42;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Reference, LValueToPointer) {
+ StringRef Snippet = "int* p; int *& target = p;";
+ EXPECT_EQ("int* p; int * const& target = p;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int* p; int * const& target = p;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+
+ EXPECT_EQ("int* p; int * const& target = p;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+ EXPECT_EQ("int* p; int * const& target = p;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Reference, LValueParens) {
+ StringRef Snippet = "int x = 42; int ((& target)) = x;";
+
+ EXPECT_EQ("int x = 42; const int ((& target)) = x;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int x = 42; const int ((& target)) = x;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+
+ EXPECT_EQ("int x = 42; int const((& target)) = x;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+ EXPECT_EQ("int x = 42; int const((& target)) = x;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Reference, ToArray) {
+ StringRef ArraySnippet = "int a[4] = {1, 2, 3, 4};";
+ StringRef Snippet = "int (&target)[4] = a;";
+ auto Cat = [&ArraySnippet](StringRef S) { return (ArraySnippet + S).str(); };
+
+ EXPECT_EQ(Cat("const int (&target)[4] = a;"),
+ runCheckOnCode<ValueLTransform>(Cat(Snippet)));
+ EXPECT_EQ(Cat("const int (&target)[4] = a;"),
+ runCheckOnCode<PointeeLTransform>(Cat(Snippet)));
+
+ EXPECT_EQ(Cat("int const(&target)[4] = a;"),
+ runCheckOnCode<ValueRTransform>(Cat(Snippet)));
+ EXPECT_EQ(Cat("int const(&target)[4] = a;"),
+ runCheckOnCode<PointeeRTransform>(Cat(Snippet)));
+}
+TEST(Reference, Auto) {
+ StringRef T = "static int global = 42; int& f() { return global; }\n";
+ StringRef S = "auto& target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const auto& target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto const& target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("const auto& target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto const& target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+
+// ----------------------------------------------------------------------------
+// Test pointers types.
+// ----------------------------------------------------------------------------
+
+TEST(Pointers, SingleBuiltin) {
+ StringRef Snippet = "int* target = nullptr;";
+
+ EXPECT_EQ("int* const target = nullptr;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int* const target = nullptr;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+
+ EXPECT_EQ("const int* target = nullptr;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("int const* target = nullptr;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Pointers, MultiBuiltin) {
+ StringRef Snippet = "int** target = nullptr;";
+
+ EXPECT_EQ("int** const target = nullptr;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int** const target = nullptr;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+
+ EXPECT_EQ("int* const* target = nullptr;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("int* const* target = nullptr;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Pointers, ToArray) {
+ StringRef ArraySnippet = "int a[4] = {1, 2, 3, 4};";
+ StringRef Snippet = "int (*target)[4] = &a;";
+ auto Cat = [&ArraySnippet](StringRef S) { return (ArraySnippet + S).str(); };
+
+ EXPECT_EQ(Cat("int (*const target)[4] = &a;"),
+ runCheckOnCode<ValueLTransform>(Cat(Snippet)));
+ EXPECT_EQ(Cat("const int (*target)[4] = &a;"),
+ runCheckOnCode<PointeeLTransform>(Cat(Snippet)));
+
+ EXPECT_EQ(Cat("int (*const target)[4] = &a;"),
+ runCheckOnCode<ValueRTransform>(Cat(Snippet)));
+ EXPECT_EQ(Cat("int const(*target)[4] = &a;"),
+ runCheckOnCode<PointeeRTransform>(Cat(Snippet)));
+}
+TEST(Pointers, Parens) {
+ StringRef Snippet = "int ((**target)) = nullptr;";
+
+ EXPECT_EQ("int ((**const target)) = nullptr;",
+ runCheckOnCode<ValueLTransform>(Snippet));
+ EXPECT_EQ("int ((**const target)) = nullptr;",
+ runCheckOnCode<ValueRTransform>(Snippet));
+
+ EXPECT_EQ("int ((* const*target)) = nullptr;",
+ runCheckOnCode<PointeeLTransform>(Snippet));
+ EXPECT_EQ("int ((* const*target)) = nullptr;",
+ runCheckOnCode<PointeeRTransform>(Snippet));
+}
+TEST(Pointers, Auto) {
+ StringRef T = "int* f() { return nullptr; }\n";
+ StringRef S = "auto* target = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("auto* const target = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto* const target = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("const auto* target = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto const* target = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Pointers, AutoParens) {
+ StringRef T = "int* f() { return nullptr; }\n";
+ StringRef S = "auto (((* target))) = f();";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("auto (((* const target))) = f();"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto (((* const target))) = f();"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("const auto (((* target))) = f();"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("auto const(((* target))) = f();"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Pointers, FunctionPointer) {
+ StringRef S = "int (*target)(float, int, double) = nullptr;";
+
+ EXPECT_EQ("int (*const target)(float, int, double) = nullptr;",
+ runCheckOnCode<ValueLTransform>(S));
+ EXPECT_EQ("int (*const target)(float, int, double) = nullptr;",
+ runCheckOnCode<ValueRTransform>(S));
+
+ EXPECT_EQ("int (*const target)(float, int, double) = nullptr;",
+ runCheckOnCode<PointeeLTransform>(S));
+ EXPECT_EQ("int (*const target)(float, int, double) = nullptr;",
+ runCheckOnCode<PointeeRTransform>(S));
+
+ S = "int (((*target)))(float, int, double) = nullptr;";
+ EXPECT_EQ("int (((*const target)))(float, int, double) = nullptr;",
+ runCheckOnCode<PointeeRTransform>(S));
+}
+TEST(Pointers, MemberFunctionPointer) {
+ StringRef T = "struct A { int f() { return 1; } };";
+ StringRef S = "int (A::*target)() = &A::f;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("int (A::*const target)() = &A::f;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("int (A::*const target)() = &A::f;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("int (A::*const target)() = &A::f;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("int (A::*const target)() = &A::f;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "int (A::*((target)))() = &A::f;";
+ EXPECT_EQ(Cat("int (A::*const ((target)))() = &A::f;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+}
+TEST(Pointers, MemberDataPointer) {
+ StringRef T = "struct A { int member = 0; };";
+ StringRef S = "int A::*target = &A::member;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("int A::*const target = &A::member;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("int A::*const target = &A::member;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("int A::*const target = &A::member;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("int A::*const target = &A::member;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "int A::*((target)) = &A::member;";
+ EXPECT_EQ(Cat("int A::*const ((target)) = &A::member;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+
+// ----------------------------------------------------------------------------
+// Test TagTypes (struct, class, unions, enums)
+// ----------------------------------------------------------------------------
+
+TEST(TagTypes, Struct) {
+ StringRef T = "struct Foo { int data; int method(); };\n";
+ StringRef S = "struct Foo target{0};";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const struct Foo target{0};"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const struct Foo target{0};"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("struct Foo const target{0};"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("struct Foo const target{0};"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo target{0};";
+ EXPECT_EQ(Cat("const Foo target{0};"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo target{0};"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const target{0};"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const target{0};"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo (target){0};";
+ EXPECT_EQ(Cat("const Foo (target){0};"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo (target){0};"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const (target){0};"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const (target){0};"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "struct S { int i; } target = { 0 };";
+ EXPECT_EQ("const struct S { int i; } target = { 0 };",
+ runCheckOnCode<ValueLTransform>(S));
+ EXPECT_EQ("const struct S { int i; } target = { 0 };",
+ runCheckOnCode<PointeeLTransform>(S));
+
+ EXPECT_EQ("struct S { int i; } const target = { 0 };",
+ runCheckOnCode<PointeeRTransform>(S));
+ EXPECT_EQ("struct S { int i; } const target = { 0 };",
+ runCheckOnCode<PointeeRTransform>(S));
+
+ S = "struct { int i; } target = { 0 };";
+ EXPECT_EQ("const struct { int i; } target = { 0 };",
+ runCheckOnCode<ValueLTransform>(S));
+ EXPECT_EQ("const struct { int i; } target = { 0 };",
+ runCheckOnCode<PointeeLTransform>(S));
+
+ EXPECT_EQ("struct { int i; } const target = { 0 };",
+ runCheckOnCode<PointeeRTransform>(S));
+ EXPECT_EQ("struct { int i; } const target = { 0 };",
+ runCheckOnCode<PointeeRTransform>(S));
+}
+TEST(TagTypes, Class) {
+ StringRef T = "class Foo { int data; int method(); };\n";
+ StringRef S = "class Foo target;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const class Foo target;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const class Foo target;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("class Foo const target;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("class Foo const target;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo target;";
+ EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo target;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const target;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo (target);";
+ EXPECT_EQ(Cat("const Foo (target);"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo (target);"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const (target);"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const (target);"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(TagTypes, Enum) {
+ StringRef T = "enum Foo { N_ONE, N_TWO, N_THREE };\n";
+ StringRef S = "enum Foo target;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const enum Foo target;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const enum Foo target;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("enum Foo const target;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("enum Foo const target;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo target;";
+ EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo target;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const target;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo (target);";
+ EXPECT_EQ(Cat("const Foo (target);"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo (target);"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const (target);"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const (target);"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(TagTypes, Union) {
+ StringRef T = "union Foo { int yay; float nej; };\n";
+ StringRef S = "union Foo target;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("const union Foo target;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const union Foo target;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("union Foo const target;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("union Foo const target;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo target;";
+ EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo target;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const target;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+
+ S = "Foo (target);";
+ EXPECT_EQ(Cat("const Foo (target);"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("const Foo (target);"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("Foo const (target);"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("Foo const (target);"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+
+// ----------------------------------------------------------------------------
+// Test Macro expansions.
+// ----------------------------------------------------------------------------
+
+TEST(Macro, AllInMacro) {
+ StringRef T = "#define DEFINE_VARIABLE int target = 42\n";
+ StringRef S = "DEFINE_VARIABLE;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("DEFINE_VARIABLE;"), runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("DEFINE_VARIABLE;"), runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("DEFINE_VARIABLE;"), runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("DEFINE_VARIABLE;"), runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Macro, MacroParameter) {
+ StringRef T = "#define DEFINE_VARIABLE(X) int X = 42\n";
+ StringRef S = "DEFINE_VARIABLE(target);";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("DEFINE_VARIABLE(target);"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("DEFINE_VARIABLE(target);"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("DEFINE_VARIABLE(target);"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("DEFINE_VARIABLE(target);"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Macro, MacroTypeValue) {
+ StringRef T = "#define BAD_TYPEDEF int\n";
+ StringRef S = "BAD_TYPEDEF target = 42;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("BAD_TYPEDEF target = 42;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("BAD_TYPEDEF target = 42;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("BAD_TYPEDEF const target = 42;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("BAD_TYPEDEF const target = 42;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+}
+TEST(Macro, MacroTypePointer) {
+ StringRef T = "#define BAD_TYPEDEF int *\n";
+ StringRef S = "BAD_TYPEDEF target = nullptr;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("BAD_TYPEDEF const target = nullptr;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("BAD_TYPEDEF const target = nullptr;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ // FIXME: Failing even all parts seem to bail-out in for isMacroID()
+ // The macro itself is changed here and below which is not intended.
+ EXPECT_NE(Cat("BAD_TYPEDEF target = nullptr;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+ EXPECT_EQ(Cat("BAD_TYPEDEF target = nullptr;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+}
+TEST(Macro, MacroTypeReference) {
+ StringRef T = "static int g = 42;\n#define BAD_TYPEDEF int&\n";
+ StringRef S = "BAD_TYPEDEF target = g;";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("BAD_TYPEDEF target = g;"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ // FIXME: Failing even all parts seem to bail-out in for isMacroID()
+ EXPECT_NE(Cat("BAD_TYPEDEF target = g;"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("BAD_TYPEDEF target = g;"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ // FIXME: Failing even all parts seem to bail-out in for isMacroID()
+ EXPECT_NE(Cat("BAD_TYPEDEF target = g;"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+// This failed in LLVM.
+TEST(Macro, Variable) {
+ StringRef M = "#define DEBUG(X) do { if (1) { X; } } while (0)\n";
+ StringRef F = "void foo() ";
+ StringRef V = "{ DEBUG(int target = 42;); }";
+
+ auto Cat = [&](StringRef S) { return (M + F + V).str(); };
+
+ EXPECT_EQ(Cat("{ DEBUG(const int target = 42;); }"),
+ runCheckOnCode<ValueLTransform>(Cat(V)));
+ EXPECT_EQ(Cat("{ DEBUG(int const target = 42;); }"),
+ runCheckOnCode<ValueRTransform>(Cat(V)));
+}
+TEST(Macro, RangeLoop) {
+ StringRef M = "#define DEBUG(X) do { if (1) { X; }} while (false)\n";
+ StringRef F = "void foo() { char array[] = {'a', 'b', 'c'}; ";
+ StringRef V = "DEBUG( for(auto& target: array) 10 + target; );";
+ StringRef E = "}";
+
+ auto Cat = [&](StringRef S) { return (M + F + V + E).str(); };
+
+ EXPECT_EQ(Cat("DEBUG( for(const auto& target: array); );"),
+ runCheckOnCode<ValueLTransform>(Cat(V)));
+ EXPECT_EQ(Cat("DEBUG( for(auto const& target: array); );"),
+ runCheckOnCode<ValueRTransform>(Cat(V)));
+}
+
+// ----------------------------------------------------------------------------
+// Test template code.
+// ----------------------------------------------------------------------------
+
+TEST(Template, TemplateVariable) {
+ StringRef T = "template <typename T> T target = 3.1415;";
+
+ EXPECT_EQ("template <typename T> const T target = 3.1415;",
+ runCheckOnCode<ValueLTransform>(T));
+ EXPECT_EQ("template <typename T> T const target = 3.1415;",
+ runCheckOnCode<ValueRTransform>(T));
+
+ EXPECT_EQ("template <typename T> const T target = 3.1415;",
+ runCheckOnCode<PointeeLTransform>(T));
+ EXPECT_EQ("template <typename T> T const target = 3.1415;",
+ runCheckOnCode<PointeeRTransform>(T));
+}
+TEST(Template, FunctionValue) {
+ StringRef T = "template <typename T> void f(T v) \n";
+ StringRef S = "{ T target = v; }";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("{ const T target = v; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const target = v; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const T target = v; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const target = v; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, FunctionPointer) {
+ StringRef T = "template <typename T> void f(T* v) \n";
+ StringRef S = "{ T* target = v; }";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("{ T* const target = v; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T* const target = v; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const T* target = v; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const* target = v; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, FunctionReference) {
+ StringRef T = "template <typename T> void f(T& v) \n";
+ StringRef S = "{ T& target = v; }";
+ auto Cat = [&T](StringRef S) { return (T + S).str(); };
+
+ EXPECT_EQ(Cat("{ const T& target = v; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const& target = v; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const T& target = v; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const& target = v; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, MultiInstantiationsFunction) {
+ StringRef T = "template <typename T> void f(T v) \n";
+ StringRef S = "{ T target = v; }";
+ StringRef InstantStart = "void calls() {\n";
+ StringRef InstValue = "f<int>(42);\n";
+ StringRef InstConstValue = "f<const int>(42);\n";
+ StringRef InstPointer = "f<int*>(nullptr);\n";
+ StringRef InstPointerConst = "f<int* const>(nullptr);\n";
+ StringRef InstConstPointer = "f<const int*>(nullptr);\n";
+ StringRef InstConstPointerConst = "f<const int* const>(nullptr);\n";
+ StringRef InstRef = "int i = 42;\nf<int&>(i);\n";
+ StringRef InstConstRef = "f<const int&>(i);\n";
+ StringRef InstantEnd = "}";
+ auto Cat = [&](StringRef Target) {
+ return (T + Target + InstantStart + InstValue + InstConstValue +
+ InstPointer + InstPointerConst + InstConstPointer +
+ InstConstPointerConst + InstRef + InstConstRef + InstantEnd)
+ .str();
+ };
+
+ EXPECT_EQ(Cat("{ const T target = v; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const target = v; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const T target = v; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const target = v; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+
+TEST(Template, StructValue) {
+ StringRef T = "template <typename T> struct S { void f(T& v) \n";
+ StringRef S = "{ T target = v; }";
+ StringRef End = "\n};";
+ auto Cat = [&T, &End](StringRef S) { return (T + S + End).str(); };
+
+ EXPECT_EQ(Cat("{ const T target = v; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const target = v; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const T target = v; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const target = v; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, StructPointer) {
+ StringRef T = "template <typename T> struct S { void f(T* v) \n";
+ StringRef S = "{ T* target = v; }";
+ StringRef End = "\n};";
+ auto Cat = [&T, &End](StringRef S) { return (T + S + End).str(); };
+
+ EXPECT_EQ(Cat("{ T* const target = v; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T* const target = v; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const T* target = v; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const* target = v; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, StructReference) {
+ StringRef T = "template <typename T> struct S { void f(T& v) \n";
+ StringRef S = "{ T& target = v; }";
+ StringRef End = "\n};";
+ auto Cat = [&T, &End](StringRef S) { return (T + S + End).str(); };
+
+ EXPECT_EQ(Cat("{ const T& target = v; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const& target = v; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const T& target = v; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ T const& target = v; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, DependentReturnFunction) {
+ StringRef TS = "template <typename T> struct TS { using value_type = T; };";
+ StringRef T = "template <typename T> void foo() ";
+ StringRef S = "{ typename T::value_type target; }";
+ auto Cat = [&TS, &T](StringRef S) { return (TS + T + S).str(); };
+
+ EXPECT_EQ(Cat("{ const typename T::value_type target; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ typename T::value_type const target; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const typename T::value_type target; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ typename T::value_type const target; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, DependentReturnPointerFunction) {
+ StringRef TS = "template <typename T> struct TS { using value_type = T; };";
+ StringRef T = "template <typename T> void foo() ";
+ StringRef S = "{ typename T::value_type *target; }";
+ auto Cat = [&TS, &T](StringRef S) { return (TS + T + S).str(); };
+
+ EXPECT_EQ(Cat("{ typename T::value_type *const target; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ typename T::value_type *const target; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const typename T::value_type *target; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ typename T::value_type const*target; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, DependentReturnReferenceFunction) {
+ StringRef TS = "template <typename T> struct TS { using value_type = T; };";
+ StringRef T = "template <typename T> void foo(T& f) ";
+ StringRef S = "{ typename T::value_type &target = f; }";
+ auto Cat = [&TS, &T](StringRef S) { return (TS + T + S).str(); };
+
+ EXPECT_EQ(Cat("{ const typename T::value_type &target = f; }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ typename T::value_type const&target = f; }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const typename T::value_type &target = f; }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ typename T::value_type const&target = f; }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, VectorLikeType) {
+ StringRef TS = "template <typename T> struct TS { TS(const T&) {} }; ";
+ StringRef T = "void foo() ";
+ StringRef S = "{ TS<int> target(42); }";
+ auto Cat = [&TS, &T](StringRef S) { return (TS + T + S).str(); };
+
+ EXPECT_EQ(Cat("{ const TS<int> target(42); }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ TS<int> const target(42); }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const TS<int> target(42); }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ TS<int> const target(42); }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+TEST(Template, SpecializedTemplate) {
+ StringRef TS = "template <typename T = int> struct TS { TS(const T&) {} }; ";
+ StringRef TS2 = "template <> struct TS<double> { TS(const double&) {} }; ";
+ StringRef T = "void foo() ";
+ StringRef S = "{ TS<double> target(42.42); }";
+ auto Cat = [&](StringRef S) { return (TS + TS2 + T + S).str(); };
+
+ EXPECT_EQ(Cat("{ const TS<double> target(42.42); }"),
+ runCheckOnCode<ValueLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ TS<double> const target(42.42); }"),
+ runCheckOnCode<ValueRTransform>(Cat(S)));
+
+ EXPECT_EQ(Cat("{ const TS<double> target(42.42); }"),
+ runCheckOnCode<PointeeLTransform>(Cat(S)));
+ EXPECT_EQ(Cat("{ TS<double> const target(42.42); }"),
+ runCheckOnCode<PointeeRTransform>(Cat(S)));
+}
+
+// -----------------------------------------------------------------------------
+// ObjC Pointers
+// -----------------------------------------------------------------------------
+
+TEST(ObjC, SimplePointers) {
+ StringRef S = "int * target = 0;";
+ EXPECT_EQ(runCheckOnCode<PointeeLTransform>(S, nullptr, "input.m"),
+ "const int * target = 0;");
+ EXPECT_EQ(runCheckOnCode<PointeeRTransform>(S, nullptr, "input.m"),
+ "int const* target = 0;");
+ EXPECT_EQ(runCheckOnCode<ValueLTransform>(S, nullptr, "input.m"),
+ "int * const target = 0;");
+ EXPECT_EQ(runCheckOnCode<ValueRTransform>(S, nullptr, "input.m"),
+ "int * const target = 0;");
+}
+TEST(ObjC, ClassPointer) {
+ StringRef TB = "@class Object;\nint main() {\n";
+ StringRef S = "Object *target;";
+ StringRef TE = "\n}";
+ auto Cat = [&](StringRef S) { return (TB + S + TE).str(); };
+
+ // FIXME: Not done properly for some reason.
+ EXPECT_NE(runCheckOnCode<PointeeLTransform>(Cat(S), nullptr, "input.m"),
+ Cat("const Object *target;"));
+ EXPECT_NE(runCheckOnCode<PointeeRTransform>(Cat(S), nullptr, "input.m"),
+ Cat("Object const*target;"));
+ EXPECT_NE(runCheckOnCode<ValueLTransform>(Cat(S), nullptr, "input.m"),
+ Cat("Object *const target;"));
+ EXPECT_NE(runCheckOnCode<ValueRTransform>(Cat(S), nullptr, "input.m"),
+ Cat("Object *const target;"));
+}
+TEST(ObjC, InterfacePointer) {
+ StringRef TB = "@interface I\n";
+ StringRef S = "- (void) foo: (int *) target;";
+ StringRef TE = "\n@end";
+ auto Cat = [&](StringRef S) { return (TB + S + TE).str(); };
+
+ EXPECT_EQ(runCheckOnCode<PointeeLTransform>(Cat(S), nullptr, "input.m"),
+ Cat("- (void) foo: (const int *) target;"));
+ EXPECT_EQ(runCheckOnCode<PointeeRTransform>(Cat(S), nullptr, "input.m"),
+ Cat("- (void) foo: (int const*) target;"));
+ // FIXME: These transformations are incorrect. ObjC seems to need
+ // RParenSkipping which is not implemented.
+ EXPECT_NE(runCheckOnCode<ValueLTransform>(Cat(S), nullptr, "input.m"),
+ Cat("- (void) foo: (int * const) target;"));
+ EXPECT_NE(runCheckOnCode<ValueRTransform>(Cat(S), nullptr, "input.m"),
+ Cat("- (void) foo: (int * const) target;"));
+}
+
+} // namespace test
+} // namespace tidy
+} // namespace clang