[clang] [clang-tools-extra] [clang analysis] ExprMutationAnalyzer support recursive forwarding reference (PR #88843)

2024-04-16 Thread Congcong Cai via cfe-commits

https://github.com/HerrCai0907 closed 
https://github.com/llvm/llvm-project/pull/88843
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang analysis] ExprMutationAnalyzer support recursive forwarding reference (PR #88843)

2024-04-16 Thread Piotr Zegar via cfe-commits

https://github.com/PiotrZSL approved this pull request.

LGTM

https://github.com/llvm/llvm-project/pull/88843
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang analysis] ExprMutationAnalyzer support recursive forwarding reference (PR #88843)

2024-04-15 Thread Congcong Cai via cfe-commits

https://github.com/HerrCai0907 edited 
https://github.com/llvm/llvm-project/pull/88843
___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [clang-tools-extra] [clang analysis] ExprMutationAnalyzer support recursive forwarding reference (PR #88843)

2024-04-15 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-analysis

Author: Congcong Cai (HerrCai0907)


Changes

Partialy fixes: #60895


---

Patch is 25.20 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/88843.diff


7 Files Affected:

- (modified) 
clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (+5-5) 
- (modified) 
clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h (+1-2) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4) 
- (modified) 
clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp 
(+15) 
- (modified) clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h 
(+93-43) 
- (modified) clang/lib/Analysis/ExprMutationAnalyzer.cpp (+72-53) 
- (modified) clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp (+30) 


``diff
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
index 2fa7cd0baf98f6..c507043c367a86 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -85,10 +85,10 @@ void UnnecessaryValueParamCheck::check(const 
MatchFinder::MatchResult ) {
 
   TraversalKindScope RAII(*Result.Context, TK_AsIs);
 
-  FunctionParmMutationAnalyzer  =
-  MutationAnalyzers.try_emplace(Function, *Function, *Result.Context)
-  .first->second;
-  if (Analyzer.isMutated(Param))
+  FunctionParmMutationAnalyzer *Analyzer =
+  FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer(
+  *Function, *Result.Context, MutationAnalyzerCache);
+  if (Analyzer->isMutated(Param))
 return;
 
   const bool IsConstQualified =
@@ -169,7 +169,7 @@ void UnnecessaryValueParamCheck::storeOptions(
 }
 
 void UnnecessaryValueParamCheck::onEndOfTranslationUnit() {
-  MutationAnalyzers.clear();
+  MutationAnalyzerCache.clear();
 }
 
 void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl ,
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
index 1872e3bc9bf29c..7250bffd20b2f9 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
@@ -37,8 +37,7 @@ class UnnecessaryValueParamCheck : public ClangTidyCheck {
   void handleMoveFix(const ParmVarDecl , const DeclRefExpr ,
  const ASTContext );
 
-  llvm::DenseMap
-  MutationAnalyzers;
+  ExprMutationAnalyzer::Memoized MutationAnalyzerCache;
   utils::IncludeInserter Inserter;
   const std::vector AllowedTypes;
 };
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 4dfbd8ca49ab9b..7095c56fe6 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -221,6 +221,10 @@ Changes in existing checks
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
 
+- Improved :doc:`misc-const-correctness
+  ` check by avoiding infinite 
recursion
+  for recursive forwarding reference.
+
 - Improved :doc:`misc-definitions-in-headers
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
index 9da468128743e9..248374a71dd40b 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
@@ -58,3 +58,18 @@ void concatenate3(Args... args)
 (..., (stream << args));
 }
 } // namespace gh70323
+
+namespace gh60895 {
+
+template  void f1(T &);
+template  void f2(T &);
+template  void f1(T &) { f2(a); }
+template  void f2(T &) { f1(a); }
+void f() {
+  int x = 0;
+  // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'x' of type 'int' can be 
declared 'const'
+  // CHECK-FIXES: int const x = 0;
+  f1(x);
+}
+
+} // namespace gh60895
diff --git a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h 
b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
index 1ceef944fbc34e..117173ba9a0958 100644
--- a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
+++ b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
@@ -8,11 +8,9 @@
 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 #define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 
-#include 
-
-#include "clang/AST/AST.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/DenseMap.h"
+#include 
 
 namespace clang {
 
@@ -21,14 +19,74 @@ class FunctionParmMutationAnalyzer;
 /// Analyzes whether any 

[clang] [clang-tools-extra] [clang analysis] ExprMutationAnalyzer support recursive forwarding reference (PR #88843)

2024-04-15 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-tools-extra

Author: Congcong Cai (HerrCai0907)


Changes

Partialy fixes: #60895


---

Patch is 25.20 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/88843.diff


7 Files Affected:

- (modified) 
clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (+5-5) 
- (modified) 
clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h (+1-2) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4) 
- (modified) 
clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp 
(+15) 
- (modified) clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h 
(+93-43) 
- (modified) clang/lib/Analysis/ExprMutationAnalyzer.cpp (+72-53) 
- (modified) clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp (+30) 


``diff
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
index 2fa7cd0baf98f6..c507043c367a86 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -85,10 +85,10 @@ void UnnecessaryValueParamCheck::check(const 
MatchFinder::MatchResult ) {
 
   TraversalKindScope RAII(*Result.Context, TK_AsIs);
 
-  FunctionParmMutationAnalyzer  =
-  MutationAnalyzers.try_emplace(Function, *Function, *Result.Context)
-  .first->second;
-  if (Analyzer.isMutated(Param))
+  FunctionParmMutationAnalyzer *Analyzer =
+  FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer(
+  *Function, *Result.Context, MutationAnalyzerCache);
+  if (Analyzer->isMutated(Param))
 return;
 
   const bool IsConstQualified =
@@ -169,7 +169,7 @@ void UnnecessaryValueParamCheck::storeOptions(
 }
 
 void UnnecessaryValueParamCheck::onEndOfTranslationUnit() {
-  MutationAnalyzers.clear();
+  MutationAnalyzerCache.clear();
 }
 
 void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl ,
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
index 1872e3bc9bf29c..7250bffd20b2f9 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
@@ -37,8 +37,7 @@ class UnnecessaryValueParamCheck : public ClangTidyCheck {
   void handleMoveFix(const ParmVarDecl , const DeclRefExpr ,
  const ASTContext );
 
-  llvm::DenseMap
-  MutationAnalyzers;
+  ExprMutationAnalyzer::Memoized MutationAnalyzerCache;
   utils::IncludeInserter Inserter;
   const std::vector AllowedTypes;
 };
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 4dfbd8ca49ab9b..7095c56fe6 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -221,6 +221,10 @@ Changes in existing checks
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
 
+- Improved :doc:`misc-const-correctness
+  ` check by avoiding infinite 
recursion
+  for recursive forwarding reference.
+
 - Improved :doc:`misc-definitions-in-headers
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
index 9da468128743e9..248374a71dd40b 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
@@ -58,3 +58,18 @@ void concatenate3(Args... args)
 (..., (stream << args));
 }
 } // namespace gh70323
+
+namespace gh60895 {
+
+template  void f1(T &);
+template  void f2(T &);
+template  void f1(T &) { f2(a); }
+template  void f2(T &) { f1(a); }
+void f() {
+  int x = 0;
+  // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'x' of type 'int' can be 
declared 'const'
+  // CHECK-FIXES: int const x = 0;
+  f1(x);
+}
+
+} // namespace gh60895
diff --git a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h 
b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
index 1ceef944fbc34e..117173ba9a0958 100644
--- a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
+++ b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
@@ -8,11 +8,9 @@
 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 #define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 
-#include 
-
-#include "clang/AST/AST.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/DenseMap.h"
+#include 
 
 namespace clang {
 
@@ -21,14 +19,74 @@ class FunctionParmMutationAnalyzer;
 /// Analyzes whether any 

[clang] [clang-tools-extra] [clang analysis] ExprMutationAnalyzer support recursive forwarding reference (PR #88843)

2024-04-15 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang

Author: Congcong Cai (HerrCai0907)


Changes

Partialy fixes: #60895


---

Patch is 25.20 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/88843.diff


7 Files Affected:

- (modified) 
clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp (+5-5) 
- (modified) 
clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h (+1-2) 
- (modified) clang-tools-extra/docs/ReleaseNotes.rst (+4) 
- (modified) 
clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp 
(+15) 
- (modified) clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h 
(+93-43) 
- (modified) clang/lib/Analysis/ExprMutationAnalyzer.cpp (+72-53) 
- (modified) clang/unittests/Analysis/ExprMutationAnalyzerTest.cpp (+30) 


``diff
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
index 2fa7cd0baf98f6..c507043c367a86 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -85,10 +85,10 @@ void UnnecessaryValueParamCheck::check(const 
MatchFinder::MatchResult ) {
 
   TraversalKindScope RAII(*Result.Context, TK_AsIs);
 
-  FunctionParmMutationAnalyzer  =
-  MutationAnalyzers.try_emplace(Function, *Function, *Result.Context)
-  .first->second;
-  if (Analyzer.isMutated(Param))
+  FunctionParmMutationAnalyzer *Analyzer =
+  FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer(
+  *Function, *Result.Context, MutationAnalyzerCache);
+  if (Analyzer->isMutated(Param))
 return;
 
   const bool IsConstQualified =
@@ -169,7 +169,7 @@ void UnnecessaryValueParamCheck::storeOptions(
 }
 
 void UnnecessaryValueParamCheck::onEndOfTranslationUnit() {
-  MutationAnalyzers.clear();
+  MutationAnalyzerCache.clear();
 }
 
 void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl ,
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
index 1872e3bc9bf29c..7250bffd20b2f9 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
@@ -37,8 +37,7 @@ class UnnecessaryValueParamCheck : public ClangTidyCheck {
   void handleMoveFix(const ParmVarDecl , const DeclRefExpr ,
  const ASTContext );
 
-  llvm::DenseMap
-  MutationAnalyzers;
+  ExprMutationAnalyzer::Memoized MutationAnalyzerCache;
   utils::IncludeInserter Inserter;
   const std::vector AllowedTypes;
 };
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 4dfbd8ca49ab9b..7095c56fe6 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -221,6 +221,10 @@ Changes in existing checks
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
 
+- Improved :doc:`misc-const-correctness
+  ` check by avoiding infinite 
recursion
+  for recursive forwarding reference.
+
 - Improved :doc:`misc-definitions-in-headers
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
index 9da468128743e9..248374a71dd40b 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
@@ -58,3 +58,18 @@ void concatenate3(Args... args)
 (..., (stream << args));
 }
 } // namespace gh70323
+
+namespace gh60895 {
+
+template  void f1(T &);
+template  void f2(T &);
+template  void f1(T &) { f2(a); }
+template  void f2(T &) { f1(a); }
+void f() {
+  int x = 0;
+  // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'x' of type 'int' can be 
declared 'const'
+  // CHECK-FIXES: int const x = 0;
+  f1(x);
+}
+
+} // namespace gh60895
diff --git a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h 
b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
index 1ceef944fbc34e..117173ba9a0958 100644
--- a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
+++ b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
@@ -8,11 +8,9 @@
 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 #define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 
-#include 
-
-#include "clang/AST/AST.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/DenseMap.h"
+#include 
 
 namespace clang {
 
@@ -21,14 +19,74 @@ class FunctionParmMutationAnalyzer;
 /// Analyzes whether any mutative 

[clang] [clang-tools-extra] [clang analysis] ExprMutationAnalyzer support recursive forwarding reference (PR #88843)

2024-04-15 Thread Congcong Cai via cfe-commits

https://github.com/HerrCai0907 created 
https://github.com/llvm/llvm-project/pull/88843

Partialy fixes: #60895


>From bfc4567ffa00d48e673f5644536c1863814ca0c3 Mon Sep 17 00:00:00 2001
From: Congcong Cai 
Date: Mon, 8 Apr 2024 09:20:58 +0800
Subject: [PATCH] [clang analysis] ExprMutationAnalyzer support recursive
 forwarding reference

Partialy fixes: #60895
---
 .../UnnecessaryValueParamCheck.cpp|  10 +-
 .../performance/UnnecessaryValueParamCheck.h  |   3 +-
 clang-tools-extra/docs/ReleaseNotes.rst   |   4 +
 .../misc/const-correctness-templates.cpp  |  15 ++
 .../Analysis/Analyses/ExprMutationAnalyzer.h  | 136 --
 clang/lib/Analysis/ExprMutationAnalyzer.cpp   | 125 +---
 .../Analysis/ExprMutationAnalyzerTest.cpp |  30 
 7 files changed, 220 insertions(+), 103 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
index 2fa7cd0baf98f6..c507043c367a86 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.cpp
@@ -85,10 +85,10 @@ void UnnecessaryValueParamCheck::check(const 
MatchFinder::MatchResult ) {
 
   TraversalKindScope RAII(*Result.Context, TK_AsIs);
 
-  FunctionParmMutationAnalyzer  =
-  MutationAnalyzers.try_emplace(Function, *Function, *Result.Context)
-  .first->second;
-  if (Analyzer.isMutated(Param))
+  FunctionParmMutationAnalyzer *Analyzer =
+  FunctionParmMutationAnalyzer::getFunctionParmMutationAnalyzer(
+  *Function, *Result.Context, MutationAnalyzerCache);
+  if (Analyzer->isMutated(Param))
 return;
 
   const bool IsConstQualified =
@@ -169,7 +169,7 @@ void UnnecessaryValueParamCheck::storeOptions(
 }
 
 void UnnecessaryValueParamCheck::onEndOfTranslationUnit() {
-  MutationAnalyzers.clear();
+  MutationAnalyzerCache.clear();
 }
 
 void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl ,
diff --git 
a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h 
b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
index 1872e3bc9bf29c..7250bffd20b2f9 100644
--- a/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
+++ b/clang-tools-extra/clang-tidy/performance/UnnecessaryValueParamCheck.h
@@ -37,8 +37,7 @@ class UnnecessaryValueParamCheck : public ClangTidyCheck {
   void handleMoveFix(const ParmVarDecl , const DeclRefExpr ,
  const ASTContext );
 
-  llvm::DenseMap
-  MutationAnalyzers;
+  ExprMutationAnalyzer::Memoized MutationAnalyzerCache;
   utils::IncludeInserter Inserter;
   const std::vector AllowedTypes;
 };
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 4dfbd8ca49ab9b..7095c56fe6 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -221,6 +221,10 @@ Changes in existing checks
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
 
+- Improved :doc:`misc-const-correctness
+  ` check by avoiding infinite 
recursion
+  for recursive forwarding reference.
+
 - Improved :doc:`misc-definitions-in-headers
   ` check by replacing the local
   option `HeaderFileExtensions` by the global option of the same name.
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
index 9da468128743e9..248374a71dd40b 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/misc/const-correctness-templates.cpp
@@ -58,3 +58,18 @@ void concatenate3(Args... args)
 (..., (stream << args));
 }
 } // namespace gh70323
+
+namespace gh60895 {
+
+template  void f1(T &);
+template  void f2(T &);
+template  void f1(T &) { f2(a); }
+template  void f2(T &) { f1(a); }
+void f() {
+  int x = 0;
+  // CHECK-MESSAGES:[[@LINE-1]]:3: warning: variable 'x' of type 'int' can be 
declared 'const'
+  // CHECK-FIXES: int const x = 0;
+  f1(x);
+}
+
+} // namespace gh60895
diff --git a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h 
b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
index 1ceef944fbc34e..117173ba9a0958 100644
--- a/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
+++ b/clang/include/clang/Analysis/Analyses/ExprMutationAnalyzer.h
@@ -8,11 +8,9 @@
 #ifndef LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 #define LLVM_CLANG_ANALYSIS_ANALYSES_EXPRMUTATIONANALYZER_H
 
-#include 
-
-#include "clang/AST/AST.h"
 #include "clang/ASTMatchers/ASTMatchers.h"
 #include "llvm/ADT/DenseMap.h"
+#include 
 
 namespace clang {
 
@@ -21,14 +19,74 @@ class FunctionParmMutationAnalyzer;
 /// Analyzes whether any mutative operations are