[clang] [clang-tools-extra] [clang-tidy] Added new check to detect redundant inline keyword (PR #73069)

Félix-Antoine Constantin via cfe-commits cfe-commits at lists.llvm.org
Wed Dec 6 15:05:32 PST 2023


https://github.com/felix642 updated https://github.com/llvm/llvm-project/pull/73069

>From 89281ccb5354e3d6349d10e6f94455556194d2d4 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Thu, 16 Nov 2023 22:03:15 -0500
Subject: [PATCH 01/12] =?UTF-8?q?[clang-tidy]=C2=A0Added=20check=20to=20de?=
 =?UTF-8?q?tect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This checks find usages of the inline keywork where it is
already implicitly defined by the compiler and suggests it's removal.

Fixes #72397
---
 .../clang-tidy/readability/CMakeLists.txt     |   1 +
 .../readability/ReadabilityTidyModule.cpp     |   3 +
 .../RedundantInlineSpecifierCheck.cpp         |  99 ++++++++++++++++
 .../RedundantInlineSpecifierCheck.h           |  36 ++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |   5 +
 .../docs/clang-tidy/checks/list.rst           |   1 +
 .../redundant-inline-specifier.rst            |  34 ++++++
 .../redundant-inline-specifier.cpp            | 110 ++++++++++++++++++
 clang/include/clang/ASTMatchers/ASTMatchers.h |   2 +-
 9 files changed, 290 insertions(+), 1 deletion(-)
 create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp

diff --git a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
index 5452c2d48a461..811310db8c721 100644
--- a/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -20,6 +20,7 @@ add_clang_library(clangTidyReadabilityModule
   IdentifierLengthCheck.cpp
   IdentifierNamingCheck.cpp
   ImplicitBoolConversionCheck.cpp
+  RedundantInlineSpecifierCheck.cpp
   InconsistentDeclarationParameterNameCheck.cpp
   IsolateDeclarationCheck.cpp
   MagicNumbersCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
index b8e6e64143206..3ce7bfecaecba 100644
--- a/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -39,6 +39,7 @@
 #include "RedundantControlFlowCheck.h"
 #include "RedundantDeclarationCheck.h"
 #include "RedundantFunctionPtrDereferenceCheck.h"
+#include "RedundantInlineSpecifierCheck.h"
 #include "RedundantMemberInitCheck.h"
 #include "RedundantPreprocessorCheck.h"
 #include "RedundantSmartptrGetCheck.h"
@@ -93,6 +94,8 @@ class ReadabilityModule : public ClangTidyModule {
         "readability-identifier-naming");
     CheckFactories.registerCheck<ImplicitBoolConversionCheck>(
         "readability-implicit-bool-conversion");
+    CheckFactories.registerCheck<RedundantInlineSpecifierCheck>(
+        "readability-redundant-inline-specifier");
     CheckFactories.registerCheck<InconsistentDeclarationParameterNameCheck>(
         "readability-inconsistent-declaration-parameter-name");
     CheckFactories.registerCheck<IsolateDeclarationCheck>(
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
new file mode 100644
index 0000000000000..e73b570df7591
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -0,0 +1,99 @@
+//===--- RedundantInlineSpecifierCheck.cpp -
+// clang-tidy----------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "RedundantInlineSpecifierCheck.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclTemplate.h"
+#include "clang/AST/ExprCXX.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Basic/SourceManager.h"
+
+#include "../utils/LexerUtils.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::readability {
+
+static std::optional<SourceLocation>
+getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
+                       const LangOptions &LangOpts) {
+  SourceLocation CurrentLocation = RangeLocation.getBegin();
+  Token CurrentToken;
+  while (!Lexer::getRawToken(CurrentLocation, CurrentToken, Sources, LangOpts,
+                             true) &&
+         CurrentLocation < RangeLocation.getEnd() &&
+         CurrentToken.isNot(tok::eof)) {
+    if (CurrentToken.is(tok::raw_identifier)) {
+      if (CurrentToken.getRawIdentifier() == "inline") {
+        return CurrentToken.getLocation();
+      }
+    }
+    CurrentLocation = CurrentToken.getEndLoc();
+  }
+  return std::nullopt;
+}
+
+void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
+  Finder->addMatcher(
+      functionDecl(unless(isExpansionInSystemHeader()), unless(isImplicit()),
+                   unless(hasAncestor(lambdaExpr())), isInline(),
+                   anyOf(isConstexpr(), isDeleted(),
+                         allOf(isDefinition(), hasAncestor(recordDecl()),
+                               unless(hasAncestor(cxxConstructorDecl())))))
+          .bind("fun_decl"),
+      this);
+
+  Finder->addMatcher(
+      varDecl(isInline(), unless(isImplicit()),
+              anyOf(allOf(isConstexpr(), unless(isStaticStorageClass())),
+                    hasAncestor(recordDecl())))
+          .bind("var_decl"),
+      this);
+
+  Finder->addMatcher(
+      functionTemplateDecl(has(functionDecl(isInline()))).bind("templ_decl"),
+      this);
+}
+
+template <typename T>
+void RedundantInlineSpecifierCheck::handleMatchedDecl(
+    const T *MatchedDecl, const SourceManager &Sources,
+    const MatchFinder::MatchResult &Result, const char *Message) {
+  if (auto Loc = getInlineTokenLocation(MatchedDecl->getSourceRange(), Sources,
+                                        Result.Context->getLangOpts()))
+    diag(*Loc, Message) << MatchedDecl << FixItHint::CreateRemoval(*Loc);
+}
+
+void RedundantInlineSpecifierCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const SourceManager &Sources = *Result.SourceManager;
+
+  if (const auto *MatchedDecl =
+          Result.Nodes.getNodeAs<FunctionDecl>("fun_decl")) {
+    handleMatchedDecl(
+        MatchedDecl, Sources, Result,
+        "Function %0 has inline specifier but is implicitly inlined");
+  } else if (const auto *MatchedDecl =
+                 Result.Nodes.getNodeAs<VarDecl>("var_decl")) {
+    handleMatchedDecl(
+        MatchedDecl, Sources, Result,
+        "Variable %0 has inline specifier but is implicitly inlined");
+  } else if (const auto *MatchedDecl =
+                 Result.Nodes.getNodeAs<FunctionTemplateDecl>("templ_decl")) {
+    handleMatchedDecl(
+        MatchedDecl, Sources, Result,
+        "Function %0 has inline specifier but is implicitly inlined");
+  }
+}
+
+} // namespace clang::tidy::readability
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
new file mode 100644
index 0000000000000..110a68504097b
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
@@ -0,0 +1,36 @@
+//===--- RedundantInlineSpecifierCheck.h - clang-tidy ------------*-C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTINLINESPECIFIERCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTINLINESPECIFIERCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::readability {
+
+/// Finds redundant `inline` specifiers in function and variable declarations.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/readability-redundant-inline-specifier.html
+class RedundantInlineSpecifierCheck : public ClangTidyCheck {
+public:
+  RedundantInlineSpecifierCheck(StringRef Name, ClangTidyContext *Context)
+      : ClangTidyCheck(Name, Context) {}
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  template <typename T>
+  void handleMatchedDecl(const T *MatchedDecl, const SourceManager &Sources,
+                         const ast_matchers::MatchFinder::MatchResult &Result,
+                         const char *Message);
+};
+
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_REDUNDANTINLINESPECIFIERCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 6d5f49dc06254..28d6c8203d38b 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -192,6 +192,11 @@ New checks
   Recommends the smallest possible underlying type for an ``enum`` or ``enum``
   class based on the range of its enumerators.
 
+- New :doc:`readability-redundant-inline-specifier
+  <clang-tidy/checks/readability/readability-redundant-inline-specifier>` check.
+
+  Detects redundant ``inline`` specifiers on function and variable declarations.
+
 - New :doc:`readability-reference-to-constructed-temporary
   <clang-tidy/checks/readability/reference-to-constructed-temporary>` check.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 6f987ba1672e3..b95d8ed64fa18 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -348,6 +348,7 @@ Clang-Tidy Checks
    :doc:`readability-identifier-length <readability/identifier-length>`,
    :doc:`readability-identifier-naming <readability/identifier-naming>`, "Yes"
    :doc:`readability-implicit-bool-conversion <readability/implicit-bool-conversion>`, "Yes"
+   :doc:`readability-redundant-inline-specifier <readability/readability-redundant-inline-specifier>`, "Yes"
    :doc:`readability-inconsistent-declaration-parameter-name <readability/inconsistent-declaration-parameter-name>`, "Yes"
    :doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes"
    :doc:`readability-magic-numbers <readability/magic-numbers>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
new file mode 100644
index 0000000000000..a066f137e0a71
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
@@ -0,0 +1,34 @@
+.. title:: clang-tidy - readability-redundant-inline-specifier
+
+readability-redundant-inline-specifier
+=================
+
+Checks for instances of the `inline` keyword in code where it is redundant
+and recommends its removal.
+
+Examples:
+
+.. code-block:: c++
+
+   constexpr inline void f() {}
+
+In the example abvove the keyword `inline` is redundant since constexpr
+functions are implicitly inlined
+
+.. code-block:: c++
+   class MyClass {
+       inline void myMethod() {}
+   };
+
+In the example above the keyword `inline` is redundant since member functions
+defined entirely inside a class/struct/union definition are implicitly inlined.
+
+The token `inline` is considered redundant in the following cases:
+
+- When it is used in a function definition that is constexpr.
+- When it is used in a member function definition that is defined entirely
+  inside a class/struct/union definition.
+- When it is used on a deleted function. 
+- When it is used on a template declaration.
+- When it is used on a member variable that is constexpr and static.
+
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
new file mode 100644
index 0000000000000..b9b143bee46f2
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
@@ -0,0 +1,110 @@
+// RUN: %check_clang_tidy %s readability-redundant-inline-specifier %t
+
+template <typename T> inline T f()
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: Function 'f' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-FIXES: template <typename T> T f()
+{
+    return T{};
+}
+
+template <> inline double f<double>() = delete;
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Function 'f<double>' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-FIXES: template <> double f<double>() = delete;
+
+inline int g(float a)
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: Function 'g' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+{
+    return static_cast<int>(a - 5.F);
+}
+
+inline int g(double) = delete;
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: Function 'g' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-FIXES: int g(double) = delete;
+
+class C
+{
+  public:
+    inline C& operator=(const C&) = delete;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: C& operator=(const C&) = delete;
+
+    constexpr inline C& operator=(int a);
+    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: constexpr C& operator=(int a);
+
+    inline C() {}
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: C() {}
+
+    constexpr inline C(int);
+    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: constexpr C(int);
+
+    inline int Get42() const { return 42; }
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: int Get42() const { return 42; }
+
+    static inline constexpr int C_STATIC = 42;
+    // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Variable 'C_STATIC' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: static constexpr int C_STATIC = 42;
+
+    static constexpr int C_STATIC_2 = 42;
+    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: Variable 'C_STATIC_2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+};
+
+constexpr inline int Get42() { return 42; }
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-FIXES: constexpr int Get42() { return 42; }
+
+
+static constexpr inline int NAMESPACE_STATIC = 42;
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:18: warning: Variable 'NAMESPACE_STATIC' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+
+inline static int fn0(int i)
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: Function 'fn0' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+{
+    return i - 1;
+}
+
+static constexpr inline int fn1(int i)
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: Function 'fn1' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-FIXES: static constexpr int fn1(int i)
+{
+    return i - 1;
+}
+
+namespace
+{
+    inline int fn2(int i)
+    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: Function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    {
+        return i - 1;
+    }
+
+    inline constexpr int fn3(int i)
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'fn3' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: constexpr int fn3(int i)
+    {
+        return i - 1;
+    }
+}
+
+namespace ns
+{
+    inline int fn4(int i)
+    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: Function 'fn4' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    {
+        return i - 1;
+    }
+
+    inline constexpr int fn5(int i)
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'fn5' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-FIXES: constexpr int fn5(int i)
+    {
+        return i - 1;
+    }
+}
+
+auto fn6 = [](){};
+//CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: Function 'operator()' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 82a26356c58f5..06e784649a975 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7889,7 +7889,7 @@ AST_POLYMORPHIC_MATCHER(isInline, AST_POLYMORPHIC_SUPPORTED_TYPES(NamespaceDecl,
   if (const auto *NSD = dyn_cast<NamespaceDecl>(&Node))
     return NSD->isInline();
   if (const auto *VD = dyn_cast<VarDecl>(&Node))
-    return VD->isInline();
+    return VD->isInlineSpecified();
   llvm_unreachable("Not a valid polymorphic type");
 }
 

>From e91d16f3a205c736904c9505e58d056427ee8b6d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Tue, 21 Nov 2023 22:00:53 -0500
Subject: [PATCH 02/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fixed Documentation
---
 clang-tools-extra/docs/ReleaseNotes.rst                        | 2 +-
 clang-tools-extra/docs/clang-tidy/checks/list.rst              | 2 +-
 .../checks/readability/redundant-inline-specifier.rst          | 3 ++-
 3 files changed, 4 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 28d6c8203d38b..f4bf855143a96 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -193,7 +193,7 @@ New checks
   class based on the range of its enumerators.
 
 - New :doc:`readability-redundant-inline-specifier
-  <clang-tidy/checks/readability/readability-redundant-inline-specifier>` check.
+  <clang-tidy/checks/readability/redundant-inline-specifier>` check.
 
   Detects redundant ``inline`` specifiers on function and variable declarations.
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index b95d8ed64fa18..07c3138f2dfd1 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -348,7 +348,7 @@ Clang-Tidy Checks
    :doc:`readability-identifier-length <readability/identifier-length>`,
    :doc:`readability-identifier-naming <readability/identifier-naming>`, "Yes"
    :doc:`readability-implicit-bool-conversion <readability/implicit-bool-conversion>`, "Yes"
-   :doc:`readability-redundant-inline-specifier <readability/readability-redundant-inline-specifier>`, "Yes"
+   :doc:`readability-redundant-inline-specifier <readability/redundant-inline-specifier>`, "Yes"
    :doc:`readability-inconsistent-declaration-parameter-name <readability/inconsistent-declaration-parameter-name>`, "Yes"
    :doc:`readability-isolate-declaration <readability/isolate-declaration>`, "Yes"
    :doc:`readability-magic-numbers <readability/magic-numbers>`,
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
index a066f137e0a71..6249064741844 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
@@ -1,7 +1,7 @@
 .. title:: clang-tidy - readability-redundant-inline-specifier
 
 readability-redundant-inline-specifier
-=================
+======================================
 
 Checks for instances of the `inline` keyword in code where it is redundant
 and recommends its removal.
@@ -16,6 +16,7 @@ In the example abvove the keyword `inline` is redundant since constexpr
 functions are implicitly inlined
 
 .. code-block:: c++
+   
    class MyClass {
        inline void myMethod() {}
    };

>From 3fadac1a7cab42eb962eaa4b6f79335e77196c4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Thu, 23 Nov 2023 18:45:56 -0500
Subject: [PATCH 03/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Code review - Fixed a few nits
---
 .../RedundantInlineSpecifierCheck.cpp         | 56 +++++++++++--------
 .../RedundantInlineSpecifierCheck.h           |  7 ++-
 .../redundant-inline-specifier.rst            | 16 +-----
 .../redundant-inline-specifier.cpp            | 40 ++++++-------
 clang/include/clang/ASTMatchers/ASTMatchers.h |  2 +-
 5 files changed, 62 insertions(+), 59 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
index e73b570df7591..65fd363ebf508 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -1,5 +1,4 @@
-//===--- RedundantInlineSpecifierCheck.cpp -
-// clang-tidy----------------------===//
+//===--- RedundantInlineSpecifierCheck.cpp - clang-tidy--------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -17,6 +16,7 @@
 #include "clang/Basic/Diagnostic.h"
 #include "clang/Basic/SourceLocation.h"
 #include "clang/Basic/SourceManager.h"
+#include "clang/Lex/Token.h"
 
 #include "../utils/LexerUtils.h"
 
@@ -24,29 +24,39 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::readability {
 
+AST_POLYMORPHIC_MATCHER(isInlineSpecified, AST_POLYMORPHIC_SUPPORTED_TYPES(
+                                                      FunctionDecl,
+                                                                  VarDecl)) {
+  if (const auto *FD = dyn_cast<FunctionDecl>(&Node))
+    return FD->isInlineSpecified();
+  if (const auto *VD = dyn_cast<VarDecl>(&Node))
+    return VD->isInlineSpecified();
+  llvm_unreachable("Not a valid polymorphic type");
+}
+
+
 static std::optional<SourceLocation>
 getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
                        const LangOptions &LangOpts) {
-  SourceLocation CurrentLocation = RangeLocation.getBegin();
-  Token CurrentToken;
-  while (!Lexer::getRawToken(CurrentLocation, CurrentToken, Sources, LangOpts,
-                             true) &&
-         CurrentLocation < RangeLocation.getEnd() &&
-         CurrentToken.isNot(tok::eof)) {
-    if (CurrentToken.is(tok::raw_identifier)) {
-      if (CurrentToken.getRawIdentifier() == "inline") {
-        return CurrentToken.getLocation();
-      }
-    }
-    CurrentLocation = CurrentToken.getEndLoc();
+  Token FirstToken;
+  Lexer::getRawToken(RangeLocation.getBegin(), FirstToken, Sources, LangOpts,
+                             true);
+  std::optional<Token> CurrentToken = FirstToken;
+  while (CurrentToken && CurrentToken->getLocation() < RangeLocation.getEnd() &&
+         CurrentToken->isNot(tok::eof)) {
+    if (CurrentToken->is(tok::raw_identifier) &&
+        CurrentToken->getRawIdentifier() == "inline")
+      return CurrentToken->getLocation();
+
+    CurrentToken = Lexer::findNextToken(CurrentToken->getLocation(), Sources, LangOpts);
   }
   return std::nullopt;
 }
 
 void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      functionDecl(unless(isExpansionInSystemHeader()), unless(isImplicit()),
-                   unless(hasAncestor(lambdaExpr())), isInline(),
+      functionDecl(unless(isExpansionInSystemHeader()),
+                   unless(hasAncestor(lambdaExpr())), isInlineSpecified(),
                    anyOf(isConstexpr(), isDeleted(),
                          allOf(isDefinition(), hasAncestor(recordDecl()),
                                unless(hasAncestor(cxxConstructorDecl())))))
@@ -54,22 +64,22 @@ void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
       this);
 
   Finder->addMatcher(
-      varDecl(isInline(), unless(isImplicit()),
+      varDecl(isInlineSpecified(),
               anyOf(allOf(isConstexpr(), unless(isStaticStorageClass())),
                     hasAncestor(recordDecl())))
           .bind("var_decl"),
       this);
 
   Finder->addMatcher(
-      functionTemplateDecl(has(functionDecl(isInline()))).bind("templ_decl"),
+      functionTemplateDecl(has(functionDecl(isInlineSpecified()))).bind("templ_decl"),
       this);
 }
 
 template <typename T>
 void RedundantInlineSpecifierCheck::handleMatchedDecl(
     const T *MatchedDecl, const SourceManager &Sources,
-    const MatchFinder::MatchResult &Result, const char *Message) {
-  if (auto Loc = getInlineTokenLocation(MatchedDecl->getSourceRange(), Sources,
+    const MatchFinder::MatchResult &Result, StringRef Message) {
+  if (std::optional<SourceLocation> Loc = getInlineTokenLocation(MatchedDecl->getSourceRange(), Sources,
                                         Result.Context->getLangOpts()))
     diag(*Loc, Message) << MatchedDecl << FixItHint::CreateRemoval(*Loc);
 }
@@ -82,17 +92,17 @@ void RedundantInlineSpecifierCheck::check(
           Result.Nodes.getNodeAs<FunctionDecl>("fun_decl")) {
     handleMatchedDecl(
         MatchedDecl, Sources, Result,
-        "Function %0 has inline specifier but is implicitly inlined");
+        "function %0 has inline specifier but is implicitly inlined");
   } else if (const auto *MatchedDecl =
                  Result.Nodes.getNodeAs<VarDecl>("var_decl")) {
     handleMatchedDecl(
         MatchedDecl, Sources, Result,
-        "Variable %0 has inline specifier but is implicitly inlined");
+        "variable %0 has inline specifier but is implicitly inlined");
   } else if (const auto *MatchedDecl =
                  Result.Nodes.getNodeAs<FunctionTemplateDecl>("templ_decl")) {
     handleMatchedDecl(
         MatchedDecl, Sources, Result,
-        "Function %0 has inline specifier but is implicitly inlined");
+        "function %0 has inline specifier but is implicitly inlined");
   }
 }
 
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
index 110a68504097b..1a510f586fcf9 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
@@ -13,7 +13,7 @@
 
 namespace clang::tidy::readability {
 
-/// Finds redundant `inline` specifiers in function and variable declarations.
+/// Detects redundant ``inline`` specifiers on function and variable declarations.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/readability/readability-redundant-inline-specifier.html
@@ -23,12 +23,15 @@ class RedundantInlineSpecifierCheck : public ClangTidyCheck {
       : ClangTidyCheck(Name, Context) {}
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
 
 private:
   template <typename T>
   void handleMatchedDecl(const T *MatchedDecl, const SourceManager &Sources,
                          const ast_matchers::MatchFinder::MatchResult &Result,
-                         const char *Message);
+                         StringRef Message);
 };
 
 } // namespace clang::tidy::readability
diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
index 6249064741844..b2757c9d8951e 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
@@ -3,7 +3,7 @@
 readability-redundant-inline-specifier
 ======================================
 
-Checks for instances of the `inline` keyword in code where it is redundant
+Checks for instances of the ``inline`` keyword in code where it is redundant
 and recommends its removal.
 
 Examples:
@@ -12,7 +12,7 @@ Examples:
 
    constexpr inline void f() {}
 
-In the example abvove the keyword `inline` is redundant since constexpr
+In the example above the keyword ``inline`` is redundant since constexpr
 functions are implicitly inlined
 
 .. code-block:: c++
@@ -21,15 +21,5 @@ functions are implicitly inlined
        inline void myMethod() {}
    };
 
-In the example above the keyword `inline` is redundant since member functions
+In the example above the keyword ``inline`` is redundant since member functions
 defined entirely inside a class/struct/union definition are implicitly inlined.
-
-The token `inline` is considered redundant in the following cases:
-
-- When it is used in a function definition that is constexpr.
-- When it is used in a member function definition that is defined entirely
-  inside a class/struct/union definition.
-- When it is used on a deleted function. 
-- When it is used on a template declaration.
-- When it is used on a member variable that is constexpr and static.
-
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
index b9b143bee46f2..15411c63060cc 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
@@ -1,73 +1,73 @@
 // RUN: %check_clang_tidy %s readability-redundant-inline-specifier %t
 
 template <typename T> inline T f()
-// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: Function 'f' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: function 'f' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 // CHECK-FIXES: template <typename T> T f()
 {
     return T{};
 }
 
 template <> inline double f<double>() = delete;
-// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: Function 'f<double>' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: function 'f<double>' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 // CHECK-FIXES: template <> double f<double>() = delete;
 
 inline int g(float a)
-// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: Function 'g' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: function 'g' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 {
     return static_cast<int>(a - 5.F);
 }
 
 inline int g(double) = delete;
-// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: Function 'g' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: function 'g' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 // CHECK-FIXES: int g(double) = delete;
 
 class C
 {
   public:
     inline C& operator=(const C&) = delete;
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: C& operator=(const C&) = delete;
 
     constexpr inline C& operator=(int a);
-    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: constexpr C& operator=(int a);
 
     inline C() {}
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: C() {}
 
     constexpr inline C(int);
-    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: Function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: constexpr C(int);
 
     inline int Get42() const { return 42; }
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: int Get42() const { return 42; }
 
     static inline constexpr int C_STATIC = 42;
-    // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: Variable 'C_STATIC' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:12: warning: variable 'C_STATIC' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: static constexpr int C_STATIC = 42;
 
     static constexpr int C_STATIC_2 = 42;
-    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: Variable 'C_STATIC_2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: variable 'C_STATIC_2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 };
 
 constexpr inline int Get42() { return 42; }
-// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: Function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES: :[[@LINE-1]]:11: warning: function 'Get42' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 // CHECK-FIXES: constexpr int Get42() { return 42; }
 
 
 static constexpr inline int NAMESPACE_STATIC = 42;
-// CHECK-MESSAGES-NOT: :[[@LINE-1]]:18: warning: Variable 'NAMESPACE_STATIC' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:18: warning: variable 'NAMESPACE_STATIC' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 
 inline static int fn0(int i)
-// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: Function 'fn0' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: function 'fn0' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 {
     return i - 1;
 }
 
 static constexpr inline int fn1(int i)
-// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: Function 'fn1' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-MESSAGES: :[[@LINE-1]]:18: warning: function 'fn1' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 // CHECK-FIXES: static constexpr int fn1(int i)
 {
     return i - 1;
@@ -76,13 +76,13 @@ static constexpr inline int fn1(int i)
 namespace
 {
     inline int fn2(int i)
-    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: Function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     {
         return i - 1;
     }
 
     inline constexpr int fn3(int i)
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'fn3' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'fn3' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: constexpr int fn3(int i)
     {
         return i - 1;
@@ -92,13 +92,13 @@ namespace
 namespace ns
 {
     inline int fn4(int i)
-    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: Function 'fn4' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: function 'fn4' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     {
         return i - 1;
     }
 
     inline constexpr int fn5(int i)
-    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: Function 'fn5' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'fn5' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: constexpr int fn5(int i)
     {
         return i - 1;
@@ -106,5 +106,5 @@ namespace ns
 }
 
 auto fn6 = [](){};
-//CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: Function 'operator()' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+//CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: function 'operator()' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 
diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h
index 06e784649a975..82a26356c58f5 100644
--- a/clang/include/clang/ASTMatchers/ASTMatchers.h
+++ b/clang/include/clang/ASTMatchers/ASTMatchers.h
@@ -7889,7 +7889,7 @@ AST_POLYMORPHIC_MATCHER(isInline, AST_POLYMORPHIC_SUPPORTED_TYPES(NamespaceDecl,
   if (const auto *NSD = dyn_cast<NamespaceDecl>(&Node))
     return NSD->isInline();
   if (const auto *VD = dyn_cast<VarDecl>(&Node))
-    return VD->isInlineSpecified();
+    return VD->isInline();
   llvm_unreachable("Not a valid polymorphic type");
 }
 

>From 06676a7677211478a1bf459f3a6c3a597b23f31f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Thu, 23 Nov 2023 18:50:44 -0500
Subject: [PATCH 04/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Removed unused part of matcher + clang-format
---
 .../RedundantInlineSpecifierCheck.cpp         | 23 ++++++++++---------
 .../RedundantInlineSpecifierCheck.h           |  3 ++-
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
index 65fd363ebf508..1b0a457740101 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -24,9 +24,9 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::readability {
 
-AST_POLYMORPHIC_MATCHER(isInlineSpecified, AST_POLYMORPHIC_SUPPORTED_TYPES(
-                                                      FunctionDecl,
-                                                                  VarDecl)) {
+AST_POLYMORPHIC_MATCHER(isInlineSpecified,
+                        AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl,
+                                                        VarDecl)) {
   if (const auto *FD = dyn_cast<FunctionDecl>(&Node))
     return FD->isInlineSpecified();
   if (const auto *VD = dyn_cast<VarDecl>(&Node))
@@ -34,13 +34,12 @@ AST_POLYMORPHIC_MATCHER(isInlineSpecified, AST_POLYMORPHIC_SUPPORTED_TYPES(
   llvm_unreachable("Not a valid polymorphic type");
 }
 
-
 static std::optional<SourceLocation>
 getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
                        const LangOptions &LangOpts) {
   Token FirstToken;
   Lexer::getRawToken(RangeLocation.getBegin(), FirstToken, Sources, LangOpts,
-                             true);
+                     true);
   std::optional<Token> CurrentToken = FirstToken;
   while (CurrentToken && CurrentToken->getLocation() < RangeLocation.getEnd() &&
          CurrentToken->isNot(tok::eof)) {
@@ -48,7 +47,8 @@ getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
         CurrentToken->getRawIdentifier() == "inline")
       return CurrentToken->getLocation();
 
-    CurrentToken = Lexer::findNextToken(CurrentToken->getLocation(), Sources, LangOpts);
+    CurrentToken =
+        Lexer::findNextToken(CurrentToken->getLocation(), Sources, LangOpts);
   }
   return std::nullopt;
 }
@@ -58,8 +58,7 @@ void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
       functionDecl(unless(isExpansionInSystemHeader()),
                    unless(hasAncestor(lambdaExpr())), isInlineSpecified(),
                    anyOf(isConstexpr(), isDeleted(),
-                         allOf(isDefinition(), hasAncestor(recordDecl()),
-                               unless(hasAncestor(cxxConstructorDecl())))))
+                         allOf(isDefinition(), hasAncestor(recordDecl()))))
           .bind("fun_decl"),
       this);
 
@@ -71,7 +70,8 @@ void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
       this);
 
   Finder->addMatcher(
-      functionTemplateDecl(has(functionDecl(isInlineSpecified()))).bind("templ_decl"),
+      functionTemplateDecl(has(functionDecl(isInlineSpecified())))
+          .bind("templ_decl"),
       this);
 }
 
@@ -79,8 +79,9 @@ template <typename T>
 void RedundantInlineSpecifierCheck::handleMatchedDecl(
     const T *MatchedDecl, const SourceManager &Sources,
     const MatchFinder::MatchResult &Result, StringRef Message) {
-  if (std::optional<SourceLocation> Loc = getInlineTokenLocation(MatchedDecl->getSourceRange(), Sources,
-                                        Result.Context->getLangOpts()))
+  if (std::optional<SourceLocation> Loc =
+          getInlineTokenLocation(MatchedDecl->getSourceRange(), Sources,
+                                 Result.Context->getLangOpts()))
     diag(*Loc, Message) << MatchedDecl << FixItHint::CreateRemoval(*Loc);
 }
 
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
index 1a510f586fcf9..b4d1f2159a41e 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
@@ -13,7 +13,8 @@
 
 namespace clang::tidy::readability {
 
-/// Detects redundant ``inline`` specifiers on function and variable declarations.
+/// Detects redundant ``inline`` specifiers on function and variable
+/// declarations.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/readability/readability-redundant-inline-specifier.html

>From e61587ef399b51eddb06946a6ca308e161dac971 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Thu, 23 Nov 2023 19:15:30 -0500
Subject: [PATCH 05/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fixed lambda expr
---
 .../clang-tidy/readability/RedundantInlineSpecifierCheck.cpp   | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
index 1b0a457740101..68dddcb3fb924 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -55,8 +55,7 @@ getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
 
 void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      functionDecl(unless(isExpansionInSystemHeader()),
-                   unless(hasAncestor(lambdaExpr())), isInlineSpecified(),
+      functionDecl(unless(isExpansionInSystemHeader()), isInlineSpecified(),
                    anyOf(isConstexpr(), isDeleted(),
                          allOf(isDefinition(), hasAncestor(recordDecl()))))
           .bind("fun_decl"),

>From fe1a9beb04e087fe5a1716a6f99043c5ad6135a5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Sat, 25 Nov 2023 12:15:15 -0500
Subject: [PATCH 06/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Fixed a few more issues

- default methods should now trigger the warning
- functions and variables in anonymous namespace should also trigger this warning
---
 .../readability/RedundantInlineSpecifierCheck.cpp         | 6 ++----
 .../readability/RedundantInlineSpecifierCheck.h           | 2 +-
 .../checkers/readability/redundant-inline-specifier.cpp   | 8 +++++++-
 3 files changed, 10 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
index 68dddcb3fb924..9dfa81a109b9d 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -55,16 +55,14 @@ getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
 
 void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      functionDecl(unless(isExpansionInSystemHeader()), isInlineSpecified(),
-                   anyOf(isConstexpr(), isDeleted(),
+      functionDecl(isInlineSpecified(), anyOf(isConstexpr(), isDeleted(), isDefaulted(), isInAnonymousNamespace(),
                          allOf(isDefinition(), hasAncestor(recordDecl()))))
           .bind("fun_decl"),
       this);
 
   Finder->addMatcher(
       varDecl(isInlineSpecified(),
-              anyOf(allOf(isConstexpr(), unless(isStaticStorageClass())),
-                    hasAncestor(recordDecl())))
+              anyOf(isInAnonymousNamespace(), allOf(isConstexpr(), hasAncestor(recordDecl()))))
           .bind("var_decl"),
       this);
 
diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
index b4d1f2159a41e..061e6c241e6c3 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h
@@ -17,7 +17,7 @@ namespace clang::tidy::readability {
 /// declarations.
 ///
 /// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/readability/readability-redundant-inline-specifier.html
+/// http://clang.llvm.org/extra/clang-tidy/checks/readability/redundant-inline-specifier.html
 class RedundantInlineSpecifierCheck : public ClangTidyCheck {
 public:
   RedundantInlineSpecifierCheck(StringRef Name, ClangTidyContext *Context)
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
index 15411c63060cc..859e03ce4bb15 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
@@ -28,6 +28,9 @@ class C
     // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: C& operator=(const C&) = delete;
 
+    inline C(const C&) = default;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+
     constexpr inline C& operator=(int a);
     // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: function 'operator=' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     // CHECK-FIXES: constexpr C& operator=(int a);
@@ -76,7 +79,7 @@ static constexpr inline int fn1(int i)
 namespace
 {
     inline int fn2(int i)
-    // CHECK-MESSAGES-NOT: :[[@LINE-1]]:5: warning: function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
     {
         return i - 1;
     }
@@ -87,6 +90,9 @@ namespace
     {
         return i - 1;
     }
+
+    inline constexpr int MY_CONSTEXPR_VAR = 42;
+    // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: variable 'MY_CONSTEXPR_VAR' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 }
 
 namespace ns

>From a6f29285c03bec652c7cd7025822b74f1cc7741e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Sat, 25 Nov 2023 12:16:46 -0500
Subject: [PATCH 07/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Code format
---
 .../readability/RedundantInlineSpecifierCheck.cpp          | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
index 9dfa81a109b9d..907a7ea6a563a 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -55,14 +55,17 @@ getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
 
 void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
-      functionDecl(isInlineSpecified(), anyOf(isConstexpr(), isDeleted(), isDefaulted(), isInAnonymousNamespace(),
+      functionDecl(isInlineSpecified(),
+                   anyOf(isConstexpr(), isDeleted(), isDefaulted(),
+                         isInAnonymousNamespace(),
                          allOf(isDefinition(), hasAncestor(recordDecl()))))
           .bind("fun_decl"),
       this);
 
   Finder->addMatcher(
       varDecl(isInlineSpecified(),
-              anyOf(isInAnonymousNamespace(), allOf(isConstexpr(), hasAncestor(recordDecl()))))
+              anyOf(isInAnonymousNamespace(),
+                    allOf(isConstexpr(), hasAncestor(recordDecl()))))
           .bind("var_decl"),
       this);
 

>From 0daf86a98d78e581f367ee0eb9472fc922ce9e22 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Sat, 25 Nov 2023 12:37:17 -0500
Subject: [PATCH 08/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Updated documentation
---
 .../checks/readability/redundant-inline-specifier.rst          | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
index b2757c9d8951e..1cb20b3fdf79b 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/readability/redundant-inline-specifier.rst
@@ -3,8 +3,7 @@
 readability-redundant-inline-specifier
 ======================================
 
-Checks for instances of the ``inline`` keyword in code where it is redundant
-and recommends its removal.
+Detects redundant ``inline`` specifiers on function and variable declarations.
 
 Examples:
 

>From 095c17ab0a1bf54ded82efe6330e0f4b1d050033 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Sat, 25 Nov 2023 12:46:33 -0500
Subject: [PATCH 09/12] =?UTF-8?q?fixup!=20fixup!=20[clang-tidy]=C2=A0Added?=
 =?UTF-8?q?=20check=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Added few test cases for forward declaration
---
 .../redundant-inline-specifier.cpp            | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
index 859e03ce4bb15..4dfdc7bd3f2bd 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
@@ -114,3 +114,22 @@ namespace ns
 auto fn6 = [](){};
 //CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: function 'operator()' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
 
+template <typename T> inline T fn7();
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: function 'fn7' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-FIXES: template <typename T> T fn7();
+
+template <typename T>  T fn7()
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: function 'fn7' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+{
+    return T{};
+}
+
+template <typename T>  T fn8();
+// CHECK-MESSAGES-NOT: :[[@LINE-1]]:1: warning: function 'fn8' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+
+template <typename T> inline T fn8()
+// CHECK-MESSAGES: :[[@LINE-1]]:23: warning: function 'fn8' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]
+// CHECK-FIXES: template <typename T> T fn8()
+{
+    return T{};
+}

>From 40ff8cdd68ac6ad2ea71f5f1262cdd4158c6e6ba Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Sat, 25 Nov 2023 12:54:02 -0500
Subject: [PATCH 10/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Disable inline variable check for pre c++-17 code
---
 .../RedundantInlineSpecifierCheck.cpp            | 16 ++++++++--------
 .../readability/redundant-inline-specifier.cpp   |  2 +-
 2 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
index 907a7ea6a563a..6dcf738a58a75 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -61,18 +61,18 @@ void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) {
                          allOf(isDefinition(), hasAncestor(recordDecl()))))
           .bind("fun_decl"),
       this);
-
-  Finder->addMatcher(
-      varDecl(isInlineSpecified(),
-              anyOf(isInAnonymousNamespace(),
-                    allOf(isConstexpr(), hasAncestor(recordDecl()))))
-          .bind("var_decl"),
-      this);
-
   Finder->addMatcher(
       functionTemplateDecl(has(functionDecl(isInlineSpecified())))
           .bind("templ_decl"),
       this);
+  if (getLangOpts().CPlusPlus17) {
+    Finder->addMatcher(
+        varDecl(isInlineSpecified(),
+                anyOf(isInAnonymousNamespace(),
+                      allOf(isConstexpr(), hasAncestor(recordDecl()))))
+            .bind("var_decl"),
+        this);
+  }
 }
 
 template <typename T>
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
index 4dfdc7bd3f2bd..f37305a2c938f 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy %s readability-redundant-inline-specifier %t
+// RUN: %check_clang_tidy %s readability-redundant-inline-specifier -std=c++17 %t
 
 template <typename T> inline T f()
 // CHECK-MESSAGES: :[[@LINE-1]]:23: warning: function 'f' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier]

>From 11b5f8ebf488c87ca37fddaf6ee3a5451caf2d2f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Wed, 6 Dec 2023 17:57:48 -0500
Subject: [PATCH 11/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Do not look for inline token in macro
---
 .../readability/RedundantInlineSpecifierCheck.cpp          | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
index 6dcf738a58a75..5bff42a32c568 100644
--- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
+++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp
@@ -37,9 +37,12 @@ AST_POLYMORPHIC_MATCHER(isInlineSpecified,
 static std::optional<SourceLocation>
 getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources,
                        const LangOptions &LangOpts) {
+  SourceLocation Loc = RangeLocation.getBegin();
+  if (Loc.isMacroID())
+    return std::nullopt;
+
   Token FirstToken;
-  Lexer::getRawToken(RangeLocation.getBegin(), FirstToken, Sources, LangOpts,
-                     true);
+  Lexer::getRawToken(Loc, FirstToken, Sources, LangOpts, true);
   std::optional<Token> CurrentToken = FirstToken;
   while (CurrentToken && CurrentToken->getLocation() < RangeLocation.getEnd() &&
          CurrentToken->isNot(tok::eof)) {

>From a72870ffd26445ea93361ac7525a0b5bcb2ae85f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?=
 <felix-antoine.constantin at polymtl.ca>
Date: Wed, 6 Dec 2023 18:05:06 -0500
Subject: [PATCH 12/12] =?UTF-8?q?fixup!=20[clang-tidy]=C2=A0Added=20check?=
 =?UTF-8?q?=20to=20detect=20redundant=20inline=20keyword?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

Added test with macro
---
 .../checkers/readability/redundant-inline-specifier.cpp     | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
index f37305a2c938f..7db9b07692f47 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/redundant-inline-specifier.cpp
@@ -133,3 +133,9 @@ template <typename T> inline T fn8()
 {
     return T{};
 }
+
+#define INLINE_MACRO() inline void fn9() { }
+INLINE_MACRO()
+
+#define INLINE_KW inline
+INLINE_KW void fn10() { }



More information about the cfe-commits mailing list