132af5bc5SAngel Garcia Gomez //===---- OverlappingReplacementsTest.cpp - clang-tidy --------------------===//
232af5bc5SAngel Garcia Gomez //
3*2946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*2946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
5*2946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
632af5bc5SAngel Garcia Gomez //
732af5bc5SAngel Garcia Gomez //===----------------------------------------------------------------------===//
832af5bc5SAngel Garcia Gomez
932af5bc5SAngel Garcia Gomez #include "ClangTidyTest.h"
1032af5bc5SAngel Garcia Gomez #include "clang/AST/RecursiveASTVisitor.h"
1132af5bc5SAngel Garcia Gomez #include "gtest/gtest.h"
1232af5bc5SAngel Garcia Gomez
1332af5bc5SAngel Garcia Gomez namespace clang {
1432af5bc5SAngel Garcia Gomez namespace tidy {
1532af5bc5SAngel Garcia Gomez namespace test {
1632af5bc5SAngel Garcia Gomez namespace {
1732af5bc5SAngel Garcia Gomez
1832af5bc5SAngel Garcia Gomez const char BoundDecl[] = "decl";
1932af5bc5SAngel Garcia Gomez const char BoundIf[] = "if";
2032af5bc5SAngel Garcia Gomez
2132af5bc5SAngel Garcia Gomez // We define a reduced set of very small checks that allow to test different
2232af5bc5SAngel Garcia Gomez // overlapping situations (no overlapping, replacements partially overlap, etc),
2332af5bc5SAngel Garcia Gomez // as well as different kinds of diagnostics (one check produces several errors,
2432af5bc5SAngel Garcia Gomez // several replacement ranges in an error, etc).
2532af5bc5SAngel Garcia Gomez class UseCharCheck : public ClangTidyCheck {
2632af5bc5SAngel Garcia Gomez public:
UseCharCheck(StringRef CheckName,ClangTidyContext * Context)2732af5bc5SAngel Garcia Gomez UseCharCheck(StringRef CheckName, ClangTidyContext *Context)
2832af5bc5SAngel Garcia Gomez : ClangTidyCheck(CheckName, Context) {}
registerMatchers(ast_matchers::MatchFinder * Finder)2932af5bc5SAngel Garcia Gomez void registerMatchers(ast_matchers::MatchFinder *Finder) override {
3032af5bc5SAngel Garcia Gomez using namespace ast_matchers;
3132af5bc5SAngel Garcia Gomez Finder->addMatcher(varDecl(hasType(isInteger())).bind(BoundDecl), this);
3232af5bc5SAngel Garcia Gomez }
check(const ast_matchers::MatchFinder::MatchResult & Result)3332af5bc5SAngel Garcia Gomez void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
3432af5bc5SAngel Garcia Gomez auto *VD = Result.Nodes.getNodeAs<VarDecl>(BoundDecl);
3543465bf3SStephen Kelly diag(VD->getBeginLoc(), "use char") << FixItHint::CreateReplacement(
3643465bf3SStephen Kelly CharSourceRange::getTokenRange(VD->getBeginLoc(), VD->getBeginLoc()),
3732af5bc5SAngel Garcia Gomez "char");
3832af5bc5SAngel Garcia Gomez }
3932af5bc5SAngel Garcia Gomez };
4032af5bc5SAngel Garcia Gomez
4132af5bc5SAngel Garcia Gomez class IfFalseCheck : public ClangTidyCheck {
4232af5bc5SAngel Garcia Gomez public:
IfFalseCheck(StringRef CheckName,ClangTidyContext * Context)4332af5bc5SAngel Garcia Gomez IfFalseCheck(StringRef CheckName, ClangTidyContext *Context)
4432af5bc5SAngel Garcia Gomez : ClangTidyCheck(CheckName, Context) {}
registerMatchers(ast_matchers::MatchFinder * Finder)4532af5bc5SAngel Garcia Gomez void registerMatchers(ast_matchers::MatchFinder *Finder) override {
4632af5bc5SAngel Garcia Gomez using namespace ast_matchers;
4732af5bc5SAngel Garcia Gomez Finder->addMatcher(ifStmt().bind(BoundIf), this);
4832af5bc5SAngel Garcia Gomez }
check(const ast_matchers::MatchFinder::MatchResult & Result)4932af5bc5SAngel Garcia Gomez void check(const ast_matchers::MatchFinder::MatchResult &Result) override {
5032af5bc5SAngel Garcia Gomez auto *If = Result.Nodes.getNodeAs<IfStmt>(BoundIf);
5132af5bc5SAngel Garcia Gomez auto *Cond = If->getCond();
5232af5bc5SAngel Garcia Gomez SourceRange Range = Cond->getSourceRange();
5332af5bc5SAngel Garcia Gomez if (auto *D = If->getConditionVariable()) {
54c09197e0SStephen Kelly Range = SourceRange(D->getBeginLoc(), D->getEndLoc());
5532af5bc5SAngel Garcia Gomez }
5632af5bc5SAngel Garcia Gomez diag(Range.getBegin(), "the cake is a lie") << FixItHint::CreateReplacement(
5732af5bc5SAngel Garcia Gomez CharSourceRange::getTokenRange(Range), "false");
5832af5bc5SAngel Garcia Gomez }
5932af5bc5SAngel Garcia Gomez };
6032af5bc5SAngel Garcia Gomez
6132af5bc5SAngel Garcia Gomez class RefactorCheck : public ClangTidyCheck {
6232af5bc5SAngel Garcia Gomez public:
RefactorCheck(StringRef CheckName,ClangTidyContext * Context)6332af5bc5SAngel Garcia Gomez RefactorCheck(StringRef CheckName, ClangTidyContext *Context)
6432af5bc5SAngel Garcia Gomez : ClangTidyCheck(CheckName, Context), NamePattern("::$") {}
RefactorCheck(StringRef CheckName,ClangTidyContext * Context,StringRef NamePattern)6532af5bc5SAngel Garcia Gomez RefactorCheck(StringRef CheckName, ClangTidyContext *Context,
6632af5bc5SAngel Garcia Gomez StringRef NamePattern)
6732af5bc5SAngel Garcia Gomez : ClangTidyCheck(CheckName, Context), NamePattern(NamePattern) {}
6832af5bc5SAngel Garcia Gomez virtual std::string newName(StringRef OldName) = 0;
6932af5bc5SAngel Garcia Gomez
registerMatchers(ast_matchers::MatchFinder * Finder)7032af5bc5SAngel Garcia Gomez void registerMatchers(ast_matchers::MatchFinder *Finder) final {
7132af5bc5SAngel Garcia Gomez using namespace ast_matchers;
7232af5bc5SAngel Garcia Gomez Finder->addMatcher(varDecl(matchesName(NamePattern)).bind(BoundDecl), this);
7332af5bc5SAngel Garcia Gomez }
7432af5bc5SAngel Garcia Gomez
check(const ast_matchers::MatchFinder::MatchResult & Result)7532af5bc5SAngel Garcia Gomez void check(const ast_matchers::MatchFinder::MatchResult &Result) final {
7632af5bc5SAngel Garcia Gomez auto *VD = Result.Nodes.getNodeAs<VarDecl>(BoundDecl);
7732af5bc5SAngel Garcia Gomez std::string NewName = newName(VD->getName());
7832af5bc5SAngel Garcia Gomez
7916693576SAngel Garcia Gomez auto Diag = diag(VD->getLocation(), "refactor %0 into %1")
8016693576SAngel Garcia Gomez << VD->getName() << NewName
8132af5bc5SAngel Garcia Gomez << FixItHint::CreateReplacement(
8232af5bc5SAngel Garcia Gomez CharSourceRange::getTokenRange(VD->getLocation(),
8332af5bc5SAngel Garcia Gomez VD->getLocation()),
8432af5bc5SAngel Garcia Gomez NewName);
8532af5bc5SAngel Garcia Gomez
8632af5bc5SAngel Garcia Gomez class UsageVisitor : public RecursiveASTVisitor<UsageVisitor> {
8732af5bc5SAngel Garcia Gomez public:
8832af5bc5SAngel Garcia Gomez UsageVisitor(const ValueDecl *VD, StringRef NewName,
8932af5bc5SAngel Garcia Gomez DiagnosticBuilder &Diag)
9032af5bc5SAngel Garcia Gomez : VD(VD), NewName(NewName), Diag(Diag) {}
9132af5bc5SAngel Garcia Gomez bool VisitDeclRefExpr(DeclRefExpr *E) {
9232af5bc5SAngel Garcia Gomez if (const ValueDecl *D = E->getDecl()) {
9332af5bc5SAngel Garcia Gomez if (VD->getCanonicalDecl() == D->getCanonicalDecl()) {
9432af5bc5SAngel Garcia Gomez Diag << FixItHint::CreateReplacement(
9532af5bc5SAngel Garcia Gomez CharSourceRange::getTokenRange(E->getSourceRange()), NewName);
9632af5bc5SAngel Garcia Gomez }
9732af5bc5SAngel Garcia Gomez }
9832af5bc5SAngel Garcia Gomez return RecursiveASTVisitor<UsageVisitor>::VisitDeclRefExpr(E);
9932af5bc5SAngel Garcia Gomez }
10032af5bc5SAngel Garcia Gomez
10132af5bc5SAngel Garcia Gomez private:
10232af5bc5SAngel Garcia Gomez const ValueDecl *VD;
10332af5bc5SAngel Garcia Gomez StringRef NewName;
10432af5bc5SAngel Garcia Gomez DiagnosticBuilder &Diag;
10532af5bc5SAngel Garcia Gomez };
10632af5bc5SAngel Garcia Gomez
10732af5bc5SAngel Garcia Gomez UsageVisitor(VD, NewName, Diag)
10832af5bc5SAngel Garcia Gomez .TraverseDecl(Result.Context->getTranslationUnitDecl());
10932af5bc5SAngel Garcia Gomez }
11032af5bc5SAngel Garcia Gomez
11132af5bc5SAngel Garcia Gomez protected:
11232af5bc5SAngel Garcia Gomez const std::string NamePattern;
11332af5bc5SAngel Garcia Gomez };
11432af5bc5SAngel Garcia Gomez
11532af5bc5SAngel Garcia Gomez class StartsWithPotaCheck : public RefactorCheck {
11632af5bc5SAngel Garcia Gomez public:
StartsWithPotaCheck(StringRef CheckName,ClangTidyContext * Context)11732af5bc5SAngel Garcia Gomez StartsWithPotaCheck(StringRef CheckName, ClangTidyContext *Context)
11832af5bc5SAngel Garcia Gomez : RefactorCheck(CheckName, Context, "::pota") {}
11932af5bc5SAngel Garcia Gomez
newName(StringRef OldName)12032af5bc5SAngel Garcia Gomez std::string newName(StringRef OldName) override {
12132af5bc5SAngel Garcia Gomez return "toma" + OldName.substr(4).str();
12232af5bc5SAngel Garcia Gomez }
12332af5bc5SAngel Garcia Gomez };
12432af5bc5SAngel Garcia Gomez
12532af5bc5SAngel Garcia Gomez class EndsWithTatoCheck : public RefactorCheck {
12632af5bc5SAngel Garcia Gomez public:
EndsWithTatoCheck(StringRef CheckName,ClangTidyContext * Context)12732af5bc5SAngel Garcia Gomez EndsWithTatoCheck(StringRef CheckName, ClangTidyContext *Context)
12832af5bc5SAngel Garcia Gomez : RefactorCheck(CheckName, Context, "tato$") {}
12932af5bc5SAngel Garcia Gomez
newName(StringRef OldName)13032af5bc5SAngel Garcia Gomez std::string newName(StringRef OldName) override {
13132af5bc5SAngel Garcia Gomez return OldName.substr(0, OldName.size() - 4).str() + "melo";
13232af5bc5SAngel Garcia Gomez }
13332af5bc5SAngel Garcia Gomez };
13432af5bc5SAngel Garcia Gomez
13532af5bc5SAngel Garcia Gomez } // namespace
13632af5bc5SAngel Garcia Gomez
TEST(OverlappingReplacementsTest,UseCharCheckTest)13732af5bc5SAngel Garcia Gomez TEST(OverlappingReplacementsTest, UseCharCheckTest) {
13832af5bc5SAngel Garcia Gomez const char Code[] =
13932af5bc5SAngel Garcia Gomez R"(void f() {
14032af5bc5SAngel Garcia Gomez int a = 0;
14132af5bc5SAngel Garcia Gomez if (int b = 0) {
14232af5bc5SAngel Garcia Gomez int c = a;
14332af5bc5SAngel Garcia Gomez }
14432af5bc5SAngel Garcia Gomez })";
14532af5bc5SAngel Garcia Gomez
14632af5bc5SAngel Garcia Gomez const char CharFix[] =
14732af5bc5SAngel Garcia Gomez R"(void f() {
14832af5bc5SAngel Garcia Gomez char a = 0;
14932af5bc5SAngel Garcia Gomez if (char b = 0) {
15032af5bc5SAngel Garcia Gomez char c = a;
15132af5bc5SAngel Garcia Gomez }
15232af5bc5SAngel Garcia Gomez })";
15332af5bc5SAngel Garcia Gomez EXPECT_EQ(CharFix, runCheckOnCode<UseCharCheck>(Code));
15432af5bc5SAngel Garcia Gomez }
15532af5bc5SAngel Garcia Gomez
TEST(OverlappingReplacementsTest,IfFalseCheckTest)15632af5bc5SAngel Garcia Gomez TEST(OverlappingReplacementsTest, IfFalseCheckTest) {
15732af5bc5SAngel Garcia Gomez const char Code[] =
15832af5bc5SAngel Garcia Gomez R"(void f() {
15932af5bc5SAngel Garcia Gomez int potato = 0;
16032af5bc5SAngel Garcia Gomez if (int b = 0) {
16132af5bc5SAngel Garcia Gomez int c = potato;
16232af5bc5SAngel Garcia Gomez } else if (true) {
16332af5bc5SAngel Garcia Gomez int d = 0;
16432af5bc5SAngel Garcia Gomez }
16532af5bc5SAngel Garcia Gomez })";
16632af5bc5SAngel Garcia Gomez
16732af5bc5SAngel Garcia Gomez const char IfFix[] =
16832af5bc5SAngel Garcia Gomez R"(void f() {
16932af5bc5SAngel Garcia Gomez int potato = 0;
17032af5bc5SAngel Garcia Gomez if (false) {
17132af5bc5SAngel Garcia Gomez int c = potato;
17232af5bc5SAngel Garcia Gomez } else if (false) {
17332af5bc5SAngel Garcia Gomez int d = 0;
17432af5bc5SAngel Garcia Gomez }
17532af5bc5SAngel Garcia Gomez })";
17632af5bc5SAngel Garcia Gomez EXPECT_EQ(IfFix, runCheckOnCode<IfFalseCheck>(Code));
17732af5bc5SAngel Garcia Gomez }
17832af5bc5SAngel Garcia Gomez
TEST(OverlappingReplacementsTest,StartsWithCheckTest)17932af5bc5SAngel Garcia Gomez TEST(OverlappingReplacementsTest, StartsWithCheckTest) {
18032af5bc5SAngel Garcia Gomez const char Code[] =
18132af5bc5SAngel Garcia Gomez R"(void f() {
18232af5bc5SAngel Garcia Gomez int a = 0;
18332af5bc5SAngel Garcia Gomez int potato = 0;
18432af5bc5SAngel Garcia Gomez if (int b = 0) {
18532af5bc5SAngel Garcia Gomez int c = potato;
18632af5bc5SAngel Garcia Gomez } else if (true) {
18732af5bc5SAngel Garcia Gomez int d = 0;
18832af5bc5SAngel Garcia Gomez }
18932af5bc5SAngel Garcia Gomez })";
19032af5bc5SAngel Garcia Gomez
19132af5bc5SAngel Garcia Gomez const char StartsFix[] =
19232af5bc5SAngel Garcia Gomez R"(void f() {
19332af5bc5SAngel Garcia Gomez int a = 0;
19432af5bc5SAngel Garcia Gomez int tomato = 0;
19532af5bc5SAngel Garcia Gomez if (int b = 0) {
19632af5bc5SAngel Garcia Gomez int c = tomato;
19732af5bc5SAngel Garcia Gomez } else if (true) {
19832af5bc5SAngel Garcia Gomez int d = 0;
19932af5bc5SAngel Garcia Gomez }
20032af5bc5SAngel Garcia Gomez })";
20132af5bc5SAngel Garcia Gomez EXPECT_EQ(StartsFix, runCheckOnCode<StartsWithPotaCheck>(Code));
20232af5bc5SAngel Garcia Gomez }
20332af5bc5SAngel Garcia Gomez
TEST(OverlappingReplacementsTest,EndsWithCheckTest)20432af5bc5SAngel Garcia Gomez TEST(OverlappingReplacementsTest, EndsWithCheckTest) {
20532af5bc5SAngel Garcia Gomez const char Code[] =
20632af5bc5SAngel Garcia Gomez R"(void f() {
20732af5bc5SAngel Garcia Gomez int a = 0;
20832af5bc5SAngel Garcia Gomez int potato = 0;
20932af5bc5SAngel Garcia Gomez if (int b = 0) {
21032af5bc5SAngel Garcia Gomez int c = potato;
21132af5bc5SAngel Garcia Gomez } else if (true) {
21232af5bc5SAngel Garcia Gomez int d = 0;
21332af5bc5SAngel Garcia Gomez }
21432af5bc5SAngel Garcia Gomez })";
21532af5bc5SAngel Garcia Gomez
21632af5bc5SAngel Garcia Gomez const char EndsFix[] =
21732af5bc5SAngel Garcia Gomez R"(void f() {
21832af5bc5SAngel Garcia Gomez int a = 0;
21932af5bc5SAngel Garcia Gomez int pomelo = 0;
22032af5bc5SAngel Garcia Gomez if (int b = 0) {
22132af5bc5SAngel Garcia Gomez int c = pomelo;
22232af5bc5SAngel Garcia Gomez } else if (true) {
22332af5bc5SAngel Garcia Gomez int d = 0;
22432af5bc5SAngel Garcia Gomez }
22532af5bc5SAngel Garcia Gomez })";
22632af5bc5SAngel Garcia Gomez EXPECT_EQ(EndsFix, runCheckOnCode<EndsWithTatoCheck>(Code));
22732af5bc5SAngel Garcia Gomez }
22832af5bc5SAngel Garcia Gomez
TEST(OverlappingReplacementTest,ReplacementsDoNotOverlap)22932af5bc5SAngel Garcia Gomez TEST(OverlappingReplacementTest, ReplacementsDoNotOverlap) {
23032af5bc5SAngel Garcia Gomez std::string Res;
23132af5bc5SAngel Garcia Gomez const char Code[] =
23232af5bc5SAngel Garcia Gomez R"(void f() {
23332af5bc5SAngel Garcia Gomez int potassium = 0;
23432af5bc5SAngel Garcia Gomez if (true) {
23532af5bc5SAngel Garcia Gomez int Potato = potassium;
23632af5bc5SAngel Garcia Gomez }
23732af5bc5SAngel Garcia Gomez })";
23832af5bc5SAngel Garcia Gomez
23932af5bc5SAngel Garcia Gomez const char CharIfFix[] =
24032af5bc5SAngel Garcia Gomez R"(void f() {
24132af5bc5SAngel Garcia Gomez char potassium = 0;
24232af5bc5SAngel Garcia Gomez if (false) {
24332af5bc5SAngel Garcia Gomez char Potato = potassium;
24432af5bc5SAngel Garcia Gomez }
24532af5bc5SAngel Garcia Gomez })";
24632af5bc5SAngel Garcia Gomez Res = runCheckOnCode<UseCharCheck, IfFalseCheck>(Code);
24732af5bc5SAngel Garcia Gomez EXPECT_EQ(CharIfFix, Res);
24832af5bc5SAngel Garcia Gomez
24932af5bc5SAngel Garcia Gomez const char StartsEndsFix[] =
25032af5bc5SAngel Garcia Gomez R"(void f() {
25132af5bc5SAngel Garcia Gomez int tomassium = 0;
25232af5bc5SAngel Garcia Gomez if (true) {
25332af5bc5SAngel Garcia Gomez int Pomelo = tomassium;
25432af5bc5SAngel Garcia Gomez }
25532af5bc5SAngel Garcia Gomez })";
25632af5bc5SAngel Garcia Gomez Res = runCheckOnCode<StartsWithPotaCheck, EndsWithTatoCheck>(Code);
25732af5bc5SAngel Garcia Gomez EXPECT_EQ(StartsEndsFix, Res);
25832af5bc5SAngel Garcia Gomez
25932af5bc5SAngel Garcia Gomez const char CharIfStartsEndsFix[] =
26032af5bc5SAngel Garcia Gomez R"(void f() {
26132af5bc5SAngel Garcia Gomez char tomassium = 0;
26232af5bc5SAngel Garcia Gomez if (false) {
26332af5bc5SAngel Garcia Gomez char Pomelo = tomassium;
26432af5bc5SAngel Garcia Gomez }
26532af5bc5SAngel Garcia Gomez })";
26632af5bc5SAngel Garcia Gomez Res = runCheckOnCode<UseCharCheck, IfFalseCheck, StartsWithPotaCheck,
26732af5bc5SAngel Garcia Gomez EndsWithTatoCheck>(Code);
26832af5bc5SAngel Garcia Gomez EXPECT_EQ(CharIfStartsEndsFix, Res);
26932af5bc5SAngel Garcia Gomez }
27032af5bc5SAngel Garcia Gomez
TEST(OverlappingReplacementsTest,ReplacementInsideOtherReplacement)27132af5bc5SAngel Garcia Gomez TEST(OverlappingReplacementsTest, ReplacementInsideOtherReplacement) {
27232af5bc5SAngel Garcia Gomez std::string Res;
27332af5bc5SAngel Garcia Gomez const char Code[] =
27432af5bc5SAngel Garcia Gomez R"(void f() {
27532af5bc5SAngel Garcia Gomez if (char potato = 0) {
27632af5bc5SAngel Garcia Gomez } else if (int a = 0) {
27732af5bc5SAngel Garcia Gomez char potato = 0;
27832af5bc5SAngel Garcia Gomez if (potato) potato;
27932af5bc5SAngel Garcia Gomez }
28032af5bc5SAngel Garcia Gomez })";
28132af5bc5SAngel Garcia Gomez
28232af5bc5SAngel Garcia Gomez // Apply the UseCharCheck together with the IfFalseCheck.
28332af5bc5SAngel Garcia Gomez //
28416693576SAngel Garcia Gomez // The 'If' fix contains the other, so that is the one that has to be applied.
28532af5bc5SAngel Garcia Gomez // } else if (int a = 0) {
28632af5bc5SAngel Garcia Gomez // ^^^ -> char
28732af5bc5SAngel Garcia Gomez // ~~~~~~~~~ -> false
28832af5bc5SAngel Garcia Gomez const char CharIfFix[] =
28932af5bc5SAngel Garcia Gomez R"(void f() {
29032af5bc5SAngel Garcia Gomez if (false) {
29132af5bc5SAngel Garcia Gomez } else if (false) {
29232af5bc5SAngel Garcia Gomez char potato = 0;
29332af5bc5SAngel Garcia Gomez if (false) potato;
29432af5bc5SAngel Garcia Gomez }
29532af5bc5SAngel Garcia Gomez })";
29632af5bc5SAngel Garcia Gomez Res = runCheckOnCode<UseCharCheck, IfFalseCheck>(Code);
29716693576SAngel Garcia Gomez EXPECT_EQ(CharIfFix, Res);
29816693576SAngel Garcia Gomez Res = runCheckOnCode<IfFalseCheck, UseCharCheck>(Code);
29916693576SAngel Garcia Gomez EXPECT_EQ(CharIfFix, Res);
30032af5bc5SAngel Garcia Gomez
30132af5bc5SAngel Garcia Gomez // Apply the IfFalseCheck with the StartsWithPotaCheck.
30232af5bc5SAngel Garcia Gomez //
30332af5bc5SAngel Garcia Gomez // The 'If' replacement is bigger here.
30432af5bc5SAngel Garcia Gomez // if (char potato = 0) {
30532af5bc5SAngel Garcia Gomez // ^^^^^^ -> tomato
30632af5bc5SAngel Garcia Gomez // ~~~~~~~~~~~~~~~ -> false
30732af5bc5SAngel Garcia Gomez //
30816693576SAngel Garcia Gomez // But the refactoring is the one that contains the other here:
30932af5bc5SAngel Garcia Gomez // char potato = 0;
31032af5bc5SAngel Garcia Gomez // ^^^^^^ -> tomato
31132af5bc5SAngel Garcia Gomez // if (potato) potato;
31232af5bc5SAngel Garcia Gomez // ^^^^^^ ^^^^^^ -> tomato, tomato
31332af5bc5SAngel Garcia Gomez // ~~~~~~ -> false
31432af5bc5SAngel Garcia Gomez const char IfStartsFix[] =
31532af5bc5SAngel Garcia Gomez R"(void f() {
31632af5bc5SAngel Garcia Gomez if (false) {
31732af5bc5SAngel Garcia Gomez } else if (false) {
31832af5bc5SAngel Garcia Gomez char tomato = 0;
31932af5bc5SAngel Garcia Gomez if (tomato) tomato;
32032af5bc5SAngel Garcia Gomez }
32132af5bc5SAngel Garcia Gomez })";
32232af5bc5SAngel Garcia Gomez Res = runCheckOnCode<IfFalseCheck, StartsWithPotaCheck>(Code);
32316693576SAngel Garcia Gomez EXPECT_EQ(IfStartsFix, Res);
32416693576SAngel Garcia Gomez Res = runCheckOnCode<StartsWithPotaCheck, IfFalseCheck>(Code);
32516693576SAngel Garcia Gomez EXPECT_EQ(IfStartsFix, Res);
32632af5bc5SAngel Garcia Gomez }
32732af5bc5SAngel Garcia Gomez
TEST(OverlappingReplacements,TwoReplacementsInsideOne)32816693576SAngel Garcia Gomez TEST(OverlappingReplacements, TwoReplacementsInsideOne) {
32916693576SAngel Garcia Gomez std::string Res;
33016693576SAngel Garcia Gomez const char Code[] =
33116693576SAngel Garcia Gomez R"(void f() {
33216693576SAngel Garcia Gomez if (int potato = 0) {
33316693576SAngel Garcia Gomez int a = 0;
33416693576SAngel Garcia Gomez }
33516693576SAngel Garcia Gomez })";
33616693576SAngel Garcia Gomez
33716693576SAngel Garcia Gomez // The two smallest replacements should not be applied.
33816693576SAngel Garcia Gomez // if (int potato = 0) {
33916693576SAngel Garcia Gomez // ^^^^^^ -> tomato
34016693576SAngel Garcia Gomez // *** -> char
34116693576SAngel Garcia Gomez // ~~~~~~~~~~~~~~ -> false
34216693576SAngel Garcia Gomez // But other errors from the same checks should not be affected.
34316693576SAngel Garcia Gomez // int a = 0;
34416693576SAngel Garcia Gomez // *** -> char
34516693576SAngel Garcia Gomez const char Fix[] =
34616693576SAngel Garcia Gomez R"(void f() {
34716693576SAngel Garcia Gomez if (false) {
34816693576SAngel Garcia Gomez char a = 0;
34916693576SAngel Garcia Gomez }
35016693576SAngel Garcia Gomez })";
35116693576SAngel Garcia Gomez Res = runCheckOnCode<UseCharCheck, IfFalseCheck, StartsWithPotaCheck>(Code);
35216693576SAngel Garcia Gomez EXPECT_EQ(Fix, Res);
35316693576SAngel Garcia Gomez Res = runCheckOnCode<StartsWithPotaCheck, IfFalseCheck, UseCharCheck>(Code);
35416693576SAngel Garcia Gomez EXPECT_EQ(Fix, Res);
35516693576SAngel Garcia Gomez }
35616693576SAngel Garcia Gomez
TEST(OverlappingReplacementsTest,ApplyAtMostOneOfTheChangesWhenPartialOverlapping)35716693576SAngel Garcia Gomez TEST(OverlappingReplacementsTest,
35816693576SAngel Garcia Gomez ApplyAtMostOneOfTheChangesWhenPartialOverlapping) {
35916693576SAngel Garcia Gomez std::string Res;
36016693576SAngel Garcia Gomez const char Code[] =
36116693576SAngel Garcia Gomez R"(void f() {
36216693576SAngel Garcia Gomez if (int potato = 0) {
36316693576SAngel Garcia Gomez int a = potato;
36416693576SAngel Garcia Gomez }
36516693576SAngel Garcia Gomez })";
36616693576SAngel Garcia Gomez
36716693576SAngel Garcia Gomez // These two replacements overlap, but none of them is completely contained
36816693576SAngel Garcia Gomez // inside the other.
36916693576SAngel Garcia Gomez // if (int potato = 0) {
37016693576SAngel Garcia Gomez // ^^^^^^ -> tomato
37116693576SAngel Garcia Gomez // ~~~~~~~~~~~~~~ -> false
37216693576SAngel Garcia Gomez // int a = potato;
37316693576SAngel Garcia Gomez // ^^^^^^ -> tomato
37416693576SAngel Garcia Gomez //
37516693576SAngel Garcia Gomez // The 'StartsWithPotaCheck' fix has endpoints inside the 'IfFalseCheck' fix,
37616693576SAngel Garcia Gomez // so it is going to be set as inapplicable. The 'if' fix will be applied.
37716693576SAngel Garcia Gomez const char IfFix[] =
37816693576SAngel Garcia Gomez R"(void f() {
37916693576SAngel Garcia Gomez if (false) {
38016693576SAngel Garcia Gomez int a = potato;
38116693576SAngel Garcia Gomez }
38216693576SAngel Garcia Gomez })";
38316693576SAngel Garcia Gomez Res = runCheckOnCode<IfFalseCheck, StartsWithPotaCheck>(Code);
38416693576SAngel Garcia Gomez EXPECT_EQ(IfFix, Res);
38516693576SAngel Garcia Gomez }
38616693576SAngel Garcia Gomez
TEST(OverlappingReplacementsTest,TwoErrorsHavePerfectOverlapping)38716693576SAngel Garcia Gomez TEST(OverlappingReplacementsTest, TwoErrorsHavePerfectOverlapping) {
38832af5bc5SAngel Garcia Gomez std::string Res;
38932af5bc5SAngel Garcia Gomez const char Code[] =
39032af5bc5SAngel Garcia Gomez R"(void f() {
39132af5bc5SAngel Garcia Gomez int potato = 0;
39232af5bc5SAngel Garcia Gomez potato += potato * potato;
39316693576SAngel Garcia Gomez if (char a = potato) potato;
39432af5bc5SAngel Garcia Gomez })";
39532af5bc5SAngel Garcia Gomez
39616693576SAngel Garcia Gomez // StartsWithPotaCheck will try to refactor 'potato' into 'tomato', and
39716693576SAngel Garcia Gomez // EndsWithTatoCheck will try to use 'pomelo'. Both fixes have the same set of
39816693576SAngel Garcia Gomez // ranges. This is a corner case of one error completely containing another:
39916693576SAngel Garcia Gomez // the other completely contains the first one as well. Both errors are
40016693576SAngel Garcia Gomez // discarded.
40116693576SAngel Garcia Gomez
40232af5bc5SAngel Garcia Gomez Res = runCheckOnCode<StartsWithPotaCheck, EndsWithTatoCheck>(Code);
40316693576SAngel Garcia Gomez EXPECT_EQ(Code, Res);
40432af5bc5SAngel Garcia Gomez }
40532af5bc5SAngel Garcia Gomez
40632af5bc5SAngel Garcia Gomez } // namespace test
40732af5bc5SAngel Garcia Gomez } // namespace tidy
40832af5bc5SAngel Garcia Gomez } // namespace clang
409