[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 14:58:18 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/11] =?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 5452c2d48a4617..811310db8c721a 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 b8e6e641432060..3ce7bfecaecba6 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 00000000000000..e73b570df75915
--- /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 00000000000000..110a68504097b3
--- /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 6d5f49dc062545..28d6c8203d38b7 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 6f987ba1672e3f..b95d8ed64fa180 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 00000000000000..a066f137e0a71c
--- /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 00000000000000..b9b143bee46f2a
--- /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 82a26356c58f55..06e784649a975b 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/11] =?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 28d6c8203d38b7..f4bf855143a963 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 b95d8ed64fa180..07c3138f2dfd1c 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 a066f137e0a71c..62490647418447 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/11] =?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 e73b570df75915..65fd363ebf5085 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 110a68504097b3..1a510f586fcf9d 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 62490647418447..b2757c9d8951e5 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 b9b143bee46f2a..15411c63060cc3 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 06e784649a975b..82a26356c58f55 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/11] =?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 65fd363ebf5085..1b0a457740101c 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 1a510f586fcf9d..b4d1f2159a41e6 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/11] =?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 1b0a457740101c..68dddcb3fb9248 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/11] =?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 68dddcb3fb9248..9dfa81a109b9d0 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 b4d1f2159a41e6..061e6c241e6c30 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 15411c63060cc3..859e03ce4bb157 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/11] =?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 9dfa81a109b9d0..907a7ea6a563a0 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/11] =?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 b2757c9d8951e5..1cb20b3fdf79b7 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/11] =?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 859e03ce4bb157..4dfdc7bd3f2bd0 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/11] =?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 907a7ea6a563a0..6dcf738a58a756 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 4dfdc7bd3f2bd0..f37305a2c938fa 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/11] =?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 6dcf738a58a756..5bff42a32c5688 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)) {
More information about the cfe-commits
mailing list