#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 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("var"); using utils::fixit::addQualifierToVarDecl; Optional 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; using PointeeRTransform = ConstTransform; using ValueLTransform = ConstTransform; using ValueRTransform = ConstTransform; // ---------------------------------------------------------------------------- // 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(Snippet)); EXPECT_EQ("const int target = 0;", runCheckOnCode(Snippet)); EXPECT_EQ("int const target = 0;", runCheckOnCode(Snippet)); EXPECT_EQ("int const target = 0;", runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const MyInt target = 0;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = 0;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = 0;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const MyInt target = nullptr;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = nullptr;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = nullptr;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const MyInt target = 0;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = 0;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = 0;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const MyInt target = nullptr;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = nullptr;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("MyInt const target = nullptr;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const auto target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const target = f();"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const auto target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const target = f();"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const auto target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const target = f();"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const decltype(f()) target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("decltype(f()) const target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("decltype(f()) const target = f();"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const decltype(f()) target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("decltype(f()) const target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("decltype(f()) const target = f();"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const decltype(f()) target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("decltype(f()) const target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("decltype(f()) const target = f();"), runCheckOnCode(Cat(S))); } TEST(Values, Parens) { StringRef Snippet = "int ((target)) = 0;"; EXPECT_EQ("const int ((target)) = 0;", runCheckOnCode(Snippet)); EXPECT_EQ("const int ((target)) = 0;", runCheckOnCode(Snippet)); EXPECT_EQ("int const ((target)) = 0;", runCheckOnCode(Snippet)); EXPECT_EQ("int const ((target)) = 0;", runCheckOnCode(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(Snippet)); EXPECT_EQ("const int target[][1] = {{1}, {2}, {3}};", runCheckOnCode(Snippet)); EXPECT_EQ("int const target[][1] = {{1}, {2}, {3}};", runCheckOnCode(Snippet)); EXPECT_EQ("int const target[][1] = {{1}, {2}, {3}};", runCheckOnCode(Snippet)); } TEST(Arrays, BuiltinParens) { StringRef Snippet = "int ((target))[][1] = {{1}, {2}, {3}};"; EXPECT_EQ("const int ((target))[][1] = {{1}, {2}, {3}};", runCheckOnCode(Snippet)); EXPECT_EQ("const int ((target))[][1] = {{1}, {2}, {3}};", runCheckOnCode(Snippet)); EXPECT_EQ("int const ((target))[][1] = {{1}, {2}, {3}};", runCheckOnCode(Snippet)); EXPECT_EQ("int const ((target))[][1] = {{1}, {2}, {3}};", runCheckOnCode(Snippet)); } TEST(Arrays, Pointers) { StringRef Snippet = "int x; int* target[] = {&x, &x, &x};"; EXPECT_EQ("int x; const int* target[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int x; int const* target[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int x; int* const target[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int x; int* const target[] = {&x, &x, &x};", runCheckOnCode(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(Snippet)); EXPECT_EQ("int* x = nullptr; int** const target[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int* x = nullptr; int* const* target[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int* x = nullptr; int** const target[] = {&x, &x, &x};", runCheckOnCode(Snippet)); } TEST(Arrays, PointersParens) { StringRef Snippet = "int x; int* (target)[] = {&x, &x, &x};"; EXPECT_EQ("int x; const int* (target)[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int x; int const* (target)[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int x; int* const (target)[] = {&x, &x, &x};", runCheckOnCode(Snippet)); EXPECT_EQ("int x; int* const (target)[] = {&x, &x, &x};", runCheckOnCode(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(Snippet)); EXPECT_EQ("int x = 42; const int& target = x;", runCheckOnCode(Snippet)); EXPECT_EQ("int x = 42; int const& target = x;", runCheckOnCode(Snippet)); EXPECT_EQ("int x = 42; int const& target = x;", runCheckOnCode(Snippet)); } TEST(Reference, RValueBuiltin) { StringRef Snippet = "int&& target = 42;"; EXPECT_EQ("const int&& target = 42;", runCheckOnCode(Snippet)); EXPECT_EQ("const int&& target = 42;", runCheckOnCode(Snippet)); EXPECT_EQ("int const&& target = 42;", runCheckOnCode(Snippet)); EXPECT_EQ("int const&& target = 42;", runCheckOnCode(Snippet)); } TEST(Reference, LValueToPointer) { StringRef Snippet = "int* p; int *& target = p;"; EXPECT_EQ("int* p; int * const& target = p;", runCheckOnCode(Snippet)); EXPECT_EQ("int* p; int * const& target = p;", runCheckOnCode(Snippet)); EXPECT_EQ("int* p; int * const& target = p;", runCheckOnCode(Snippet)); EXPECT_EQ("int* p; int * const& target = p;", runCheckOnCode(Snippet)); } TEST(Reference, LValueParens) { StringRef Snippet = "int x = 42; int ((& target)) = x;"; EXPECT_EQ("int x = 42; const int ((& target)) = x;", runCheckOnCode(Snippet)); EXPECT_EQ("int x = 42; const int ((& target)) = x;", runCheckOnCode(Snippet)); EXPECT_EQ("int x = 42; int const((& target)) = x;", runCheckOnCode(Snippet)); EXPECT_EQ("int x = 42; int const((& target)) = x;", runCheckOnCode(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(Cat(Snippet))); EXPECT_EQ(Cat("const int (&target)[4] = a;"), runCheckOnCode(Cat(Snippet))); EXPECT_EQ(Cat("int const(&target)[4] = a;"), runCheckOnCode(Cat(Snippet))); EXPECT_EQ(Cat("int const(&target)[4] = a;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("auto const& target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const auto& target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const& target = f();"), runCheckOnCode(Cat(S))); } // ---------------------------------------------------------------------------- // Test pointers types. // ---------------------------------------------------------------------------- TEST(Pointers, SingleBuiltin) { StringRef Snippet = "int* target = nullptr;"; EXPECT_EQ("int* const target = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int* const target = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("const int* target = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int const* target = nullptr;", runCheckOnCode(Snippet)); } TEST(Pointers, MultiBuiltin) { StringRef Snippet = "int** target = nullptr;"; EXPECT_EQ("int** const target = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int** const target = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int* const* target = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int* const* target = nullptr;", runCheckOnCode(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(Cat(Snippet))); EXPECT_EQ(Cat("const int (*target)[4] = &a;"), runCheckOnCode(Cat(Snippet))); EXPECT_EQ(Cat("int (*const target)[4] = &a;"), runCheckOnCode(Cat(Snippet))); EXPECT_EQ(Cat("int const(*target)[4] = &a;"), runCheckOnCode(Cat(Snippet))); } TEST(Pointers, Parens) { StringRef Snippet = "int ((**target)) = nullptr;"; EXPECT_EQ("int ((**const target)) = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int ((**const target)) = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int ((* const*target)) = nullptr;", runCheckOnCode(Snippet)); EXPECT_EQ("int ((* const*target)) = nullptr;", runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("auto* const target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const auto* target = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const* target = f();"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("auto (((* const target))) = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const auto (((* target))) = f();"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("auto const(((* target))) = f();"), runCheckOnCode(Cat(S))); } TEST(Pointers, FunctionPointer) { StringRef S = "int (*target)(float, int, double) = nullptr;"; EXPECT_EQ("int (*const target)(float, int, double) = nullptr;", runCheckOnCode(S)); EXPECT_EQ("int (*const target)(float, int, double) = nullptr;", runCheckOnCode(S)); EXPECT_EQ("int (*const target)(float, int, double) = nullptr;", runCheckOnCode(S)); EXPECT_EQ("int (*const target)(float, int, double) = nullptr;", runCheckOnCode(S)); S = "int (((*target)))(float, int, double) = nullptr;"; EXPECT_EQ("int (((*const target)))(float, int, double) = nullptr;", runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("int (A::*const target)() = &A::f;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("int (A::*const target)() = &A::f;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("int (A::*const target)() = &A::f;"), runCheckOnCode(Cat(S))); S = "int (A::*((target)))() = &A::f;"; EXPECT_EQ(Cat("int (A::*const ((target)))() = &A::f;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("int A::*const target = &A::member;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("int A::*const target = &A::member;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("int A::*const target = &A::member;"), runCheckOnCode(Cat(S))); S = "int A::*((target)) = &A::member;"; EXPECT_EQ(Cat("int A::*const ((target)) = &A::member;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const struct Foo target{0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("struct Foo const target{0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("struct Foo const target{0};"), runCheckOnCode(Cat(S))); S = "Foo target{0};"; EXPECT_EQ(Cat("const Foo target{0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo target{0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target{0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target{0};"), runCheckOnCode(Cat(S))); S = "Foo (target){0};"; EXPECT_EQ(Cat("const Foo (target){0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo (target){0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target){0};"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target){0};"), runCheckOnCode(Cat(S))); S = "struct S { int i; } target = { 0 };"; EXPECT_EQ("const struct S { int i; } target = { 0 };", runCheckOnCode(S)); EXPECT_EQ("const struct S { int i; } target = { 0 };", runCheckOnCode(S)); EXPECT_EQ("struct S { int i; } const target = { 0 };", runCheckOnCode(S)); EXPECT_EQ("struct S { int i; } const target = { 0 };", runCheckOnCode(S)); S = "struct { int i; } target = { 0 };"; EXPECT_EQ("const struct { int i; } target = { 0 };", runCheckOnCode(S)); EXPECT_EQ("const struct { int i; } target = { 0 };", runCheckOnCode(S)); EXPECT_EQ("struct { int i; } const target = { 0 };", runCheckOnCode(S)); EXPECT_EQ("struct { int i; } const target = { 0 };", runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const class Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("class Foo const target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("class Foo const target;"), runCheckOnCode(Cat(S))); S = "Foo target;"; EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode(Cat(S))); S = "Foo (target);"; EXPECT_EQ(Cat("const Foo (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target);"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const enum Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("enum Foo const target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("enum Foo const target;"), runCheckOnCode(Cat(S))); S = "Foo target;"; EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode(Cat(S))); S = "Foo (target);"; EXPECT_EQ(Cat("const Foo (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target);"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("const union Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("union Foo const target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("union Foo const target;"), runCheckOnCode(Cat(S))); S = "Foo target;"; EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const target;"), runCheckOnCode(Cat(S))); S = "Foo (target);"; EXPECT_EQ(Cat("const Foo (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("const Foo (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("Foo const (target);"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("DEFINE_VARIABLE;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("DEFINE_VARIABLE;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("DEFINE_VARIABLE;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("DEFINE_VARIABLE(target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("DEFINE_VARIABLE(target);"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("DEFINE_VARIABLE(target);"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("BAD_TYPEDEF target = 42;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("BAD_TYPEDEF const target = 42;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("BAD_TYPEDEF const target = 42;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("BAD_TYPEDEF const target = nullptr;"), runCheckOnCode(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(Cat(S))); EXPECT_EQ(Cat("BAD_TYPEDEF target = nullptr;"), runCheckOnCode(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(Cat(S))); // FIXME: Failing even all parts seem to bail-out in for isMacroID() EXPECT_NE(Cat("BAD_TYPEDEF target = g;"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("BAD_TYPEDEF target = g;"), runCheckOnCode(Cat(S))); // FIXME: Failing even all parts seem to bail-out in for isMacroID() EXPECT_NE(Cat("BAD_TYPEDEF target = g;"), runCheckOnCode(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(Cat(V))); EXPECT_EQ(Cat("{ DEBUG(int const target = 42;); }"), runCheckOnCode(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(Cat(V))); EXPECT_EQ(Cat("DEBUG( for(auto const& target: array); );"), runCheckOnCode(Cat(V))); } // ---------------------------------------------------------------------------- // Test template code. // ---------------------------------------------------------------------------- TEST(Template, TemplateVariable) { StringRef T = "template T target = 3.1415;"; EXPECT_EQ("template const T target = 3.1415;", runCheckOnCode(T)); EXPECT_EQ("template T const target = 3.1415;", runCheckOnCode(T)); EXPECT_EQ("template const T target = 3.1415;", runCheckOnCode(T)); EXPECT_EQ("template T const target = 3.1415;", runCheckOnCode(T)); } TEST(Template, FunctionValue) { StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ T const target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const T target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ T const target = v; }"), runCheckOnCode(Cat(S))); } TEST(Template, FunctionPointer) { StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ T* const target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const T* target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ T const* target = v; }"), runCheckOnCode(Cat(S))); } TEST(Template, FunctionReference) { StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ T const& target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const T& target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ T const& target = v; }"), runCheckOnCode(Cat(S))); } TEST(Template, MultiInstantiationsFunction) { StringRef T = "template void f(T v) \n"; StringRef S = "{ T target = v; }"; StringRef InstantStart = "void calls() {\n"; StringRef InstValue = "f(42);\n"; StringRef InstConstValue = "f(42);\n"; StringRef InstPointer = "f(nullptr);\n"; StringRef InstPointerConst = "f(nullptr);\n"; StringRef InstConstPointer = "f(nullptr);\n"; StringRef InstConstPointerConst = "f(nullptr);\n"; StringRef InstRef = "int i = 42;\nf(i);\n"; StringRef InstConstRef = "f(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(Cat(S))); EXPECT_EQ(Cat("{ T const target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const T target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ T const target = v; }"), runCheckOnCode(Cat(S))); } TEST(Template, StructValue) { StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ T const target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const T target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ T const target = v; }"), runCheckOnCode(Cat(S))); } TEST(Template, StructPointer) { StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ T* const target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const T* target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ T const* target = v; }"), runCheckOnCode(Cat(S))); } TEST(Template, StructReference) { StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ T const& target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const T& target = v; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ T const& target = v; }"), runCheckOnCode(Cat(S))); } TEST(Template, DependentReturnFunction) { StringRef TS = "template struct TS { using value_type = T; };"; StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ typename T::value_type const target; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const typename T::value_type target; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ typename T::value_type const target; }"), runCheckOnCode(Cat(S))); } TEST(Template, DependentReturnPointerFunction) { StringRef TS = "template struct TS { using value_type = T; };"; StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ typename T::value_type *const target; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const typename T::value_type *target; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ typename T::value_type const*target; }"), runCheckOnCode(Cat(S))); } TEST(Template, DependentReturnReferenceFunction) { StringRef TS = "template struct TS { using value_type = T; };"; StringRef T = "template 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(Cat(S))); EXPECT_EQ(Cat("{ typename T::value_type const&target = f; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const typename T::value_type &target = f; }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ typename T::value_type const&target = f; }"), runCheckOnCode(Cat(S))); } TEST(Template, VectorLikeType) { StringRef TS = "template struct TS { TS(const T&) {} }; "; StringRef T = "void foo() "; StringRef S = "{ TS target(42); }"; auto Cat = [&TS, &T](StringRef S) { return (TS + T + S).str(); }; EXPECT_EQ(Cat("{ const TS target(42); }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ TS const target(42); }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const TS target(42); }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ TS const target(42); }"), runCheckOnCode(Cat(S))); } TEST(Template, SpecializedTemplate) { StringRef TS = "template struct TS { TS(const T&) {} }; "; StringRef TS2 = "template <> struct TS { TS(const double&) {} }; "; StringRef T = "void foo() "; StringRef S = "{ TS target(42.42); }"; auto Cat = [&](StringRef S) { return (TS + TS2 + T + S).str(); }; EXPECT_EQ(Cat("{ const TS target(42.42); }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ TS const target(42.42); }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ const TS target(42.42); }"), runCheckOnCode(Cat(S))); EXPECT_EQ(Cat("{ TS const target(42.42); }"), runCheckOnCode(Cat(S))); } // ----------------------------------------------------------------------------- // ObjC Pointers // ----------------------------------------------------------------------------- TEST(ObjC, SimplePointers) { StringRef S = "int * target = 0;"; EXPECT_EQ(runCheckOnCode(S, nullptr, "input.m"), "const int * target = 0;"); EXPECT_EQ(runCheckOnCode(S, nullptr, "input.m"), "int const* target = 0;"); EXPECT_EQ(runCheckOnCode(S, nullptr, "input.m"), "int * const target = 0;"); EXPECT_EQ(runCheckOnCode(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(Cat(S), nullptr, "input.m"), Cat("const Object *target;")); EXPECT_NE(runCheckOnCode(Cat(S), nullptr, "input.m"), Cat("Object const*target;")); EXPECT_NE(runCheckOnCode(Cat(S), nullptr, "input.m"), Cat("Object *const target;")); EXPECT_NE(runCheckOnCode(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(Cat(S), nullptr, "input.m"), Cat("- (void) foo: (const int *) target;")); EXPECT_EQ(runCheckOnCode(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(Cat(S), nullptr, "input.m"), Cat("- (void) foo: (int * const) target;")); EXPECT_NE(runCheckOnCode(Cat(S), nullptr, "input.m"), Cat("- (void) foo: (int * const) target;")); } } // namespace test } // namespace tidy } // namespace clang