Index: clang-tidy/utils/ExprMutationAnalyzer.cpp =================================================================== --- clang-tidy/utils/ExprMutationAnalyzer.cpp +++ clang-tidy/utils/ExprMutationAnalyzer.cpp @@ -48,7 +48,8 @@ } const auto nonConstReferenceType = [] { - return referenceType(pointee(unless(isConstQualified()))); + return hasUnqualifiedDesugaredType( + referenceType(pointee(unless(isConstQualified())))); }; } // namespace Index: unittests/clang-tidy/ExprMutationAnalyzerTest.cpp =================================================================== --- unittests/clang-tidy/ExprMutationAnalyzerTest.cpp +++ unittests/clang-tidy/ExprMutationAnalyzerTest.cpp @@ -191,6 +191,24 @@ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); + AST = tooling::buildASTFromCode("typedef int& IntRef;" + "void g(IntRef); void f() { int x; g(x); }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); + + AST = + tooling::buildASTFromCode("template using TRef = T&;" + "void g(TRef); void f() { int x; g(x); }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); + + AST = tooling::buildASTFromCode( + "template struct identity { using type = T; };" + "template void g(typename identity::type);" + "void f() { int x; g(x); }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("g(x)")); + AST = tooling::buildASTFromCode( "void f() { struct A {}; A operator+(A&, int); A x; x + 1; }"); Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); @@ -214,6 +232,25 @@ match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_FALSE(isMutated(Results, AST.get())); + AST = tooling::buildASTFromCode("typedef const int& CIntRef;" + "void g(CIntRef); void f() { int x; g(x); }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isMutated(Results, AST.get())); + + AST = tooling::buildASTFromCode( + "template using CTRef = const T&;" + "void g(CTRef); void f() { int x; g(x); }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isMutated(Results, AST.get())); + + AST = tooling::buildASTFromCode( + "template struct identity { using type = T; };" + "template " + "void g(typename identity::type);" + "void f() { int x; g(x); }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isMutated(Results, AST.get())); + AST = tooling::buildASTFromCode( "void f() { struct A {}; A operator+(const A&, int); A x; x + 1; }"); Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); @@ -440,22 +477,44 @@ } TEST(ExprMutationAnalyzerTest, FollowRefModified) { - const auto AST = tooling::buildASTFromCode( + auto AST = tooling::buildASTFromCode( "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " "int& r3 = r2; r3 = 10; }"); - const auto Results = + auto Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("r0", "r1", "r2", "r3", "r3 = 10")); + + AST = tooling::buildASTFromCode( + "typedef int& IntRefX;" + "using IntRefY = int&;" + "void f() { int x; IntRefX r0 = x; IntRefY r1 = r0;" + "decltype((x)) r2 = r1; r2 = 10; }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_THAT(mutatedBy(Results, AST.get()), + ElementsAre("r0", "r1", "r2", "r2 = 10")); } TEST(ExprMutationAnalyzerTest, FollowRefNotModified) { - const auto AST = tooling::buildASTFromCode( + auto AST = tooling::buildASTFromCode( "void f() { int x; int& r0 = x; int& r1 = r0; int& r2 = r1; " "int& r3 = r2; int& r4 = r3; int& r5 = r4;}"); - const auto Results = + auto Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_FALSE(isMutated(Results, AST.get())); + + AST = tooling::buildASTFromCode( + "void f() { int x; int& r0 = x; const int& r1 = r0;}"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isMutated(Results, AST.get())); + + AST = tooling::buildASTFromCode( + "typedef const int& CIntRefX;" + "using CIntRefY = const int&;" + "void f() { int x; int& r0 = x; CIntRefX r1 = r0;" + "CIntRefY r2 = r1; decltype((r1)) r3 = r2;}"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, FollowConditionalRefModified) { @@ -542,12 +601,19 @@ } TEST(ExprMutationAnalyzerTest, CastToRefModified) { - const auto AST = tooling::buildASTFromCode( + auto AST = tooling::buildASTFromCode( "void f() { int x; static_cast(x) = 10; }"); - const auto Results = + auto Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("static_cast(x) = 10")); + + AST = tooling::buildASTFromCode( + "typedef int& IntRef;" + "void f() { int x; static_cast(x) = 10; }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_THAT(mutatedBy(Results, AST.get()), + ElementsAre("static_cast(x) = 10")); } TEST(ExprMutationAnalyzerTest, CastToRefNotModified) { @@ -559,11 +625,17 @@ } TEST(ExprMutationAnalyzerTest, CastToConstRef) { - const auto AST = tooling::buildASTFromCode( + auto AST = tooling::buildASTFromCode( "void f() { int x; static_cast(x); }"); - const auto Results = + auto Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_FALSE(isMutated(Results, AST.get())); + + AST = + tooling::buildASTFromCode("typedef const int& CIntRef;" + "void f() { int x; static_cast(x); }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, LambdaDefaultCaptureByValue) { @@ -601,11 +673,17 @@ } TEST(ExprMutationAnalyzerTest, RangeForArrayByRefModified) { - const auto AST = tooling::buildASTFromCode( + auto AST = tooling::buildASTFromCode( "void f() { int x[2]; for (int& e : x) e = 10; }"); - const auto Results = + auto Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); + + AST = tooling::buildASTFromCode( + "typedef int& IntRef;" + "void f() { int x[2]; for (IntRef e : x) e = 10; }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_THAT(mutatedBy(Results, AST.get()), ElementsAre("e", "e = 10")); } TEST(ExprMutationAnalyzerTest, RangeForArrayByRefNotModified) { @@ -625,11 +703,17 @@ } TEST(ExprMutationAnalyzerTest, RangeForArrayByConstRef) { - const auto AST = tooling::buildASTFromCode( + auto AST = tooling::buildASTFromCode( "void f() { int x[2]; for (const int& e : x) e; }"); - const auto Results = + auto Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); EXPECT_FALSE(isMutated(Results, AST.get())); + + AST = tooling::buildASTFromCode( + "typedef const int& CIntRef;" + "void f() { int x[2]; for (CIntRef e : x) e; }"); + Results = match(withEnclosingCompound(declRefTo("x")), AST->getASTContext()); + EXPECT_FALSE(isMutated(Results, AST.get())); } TEST(ExprMutationAnalyzerTest, RangeForNonArrayByRefModified) {