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.constan...@polymtl.ca> Date: Thu, 16 Nov 2023 22:03:15 -0500 Subject: [PATCH 01/13] =?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.constan...@polymtl.ca> Date: Tue, 21 Nov 2023 22:00:53 -0500 Subject: [PATCH 02/13] =?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.constan...@polymtl.ca> Date: Thu, 23 Nov 2023 18:45:56 -0500 Subject: [PATCH 03/13] =?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.constan...@polymtl.ca> Date: Thu, 23 Nov 2023 18:50:44 -0500 Subject: [PATCH 04/13] =?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.constan...@polymtl.ca> Date: Thu, 23 Nov 2023 19:15:30 -0500 Subject: [PATCH 05/13] =?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.constan...@polymtl.ca> Date: Sat, 25 Nov 2023 12:15:15 -0500 Subject: [PATCH 06/13] =?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.constan...@polymtl.ca> Date: Sat, 25 Nov 2023 12:16:46 -0500 Subject: [PATCH 07/13] =?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.constan...@polymtl.ca> Date: Sat, 25 Nov 2023 12:37:17 -0500 Subject: [PATCH 08/13] =?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.constan...@polymtl.ca> Date: Sat, 25 Nov 2023 12:46:33 -0500 Subject: [PATCH 09/13] =?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.constan...@polymtl.ca> Date: Sat, 25 Nov 2023 12:54:02 -0500 Subject: [PATCH 10/13] =?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.constan...@polymtl.ca> Date: Wed, 6 Dec 2023 17:57:48 -0500 Subject: [PATCH 11/13] =?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)) { From a72870ffd26445ea93361ac7525a0b5bcb2ae85f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= <felix-antoine.constan...@polymtl.ca> Date: Wed, 6 Dec 2023 18:05:06 -0500 Subject: [PATCH 12/13] =?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 f37305a2c938fa..7db9b07692f47d 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() { } From 3ec09df890df6865849b71d14935598da630d3e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix-Antoine=20Constantin?= <felix-antoine.constan...@polymtl.ca> Date: Mon, 18 Dec 2023 20:50:50 -0500 Subject: [PATCH 13/13] =?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 StrictMode option to decide if we want to flag redundant inline specifiers rather than implicit ones --- .../RedundantInlineSpecifierCheck.cpp | 49 +++++++++++++------ .../RedundantInlineSpecifierCheck.h | 4 +- .../redundant-inline-specifier.rst | 8 +++ .../redundant-inline-specifier.cpp | 32 ++++++------ 4 files changed, 59 insertions(+), 34 deletions(-) diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp index 5bff42a32c5688..0e8d17d4442478 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp +++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.cpp @@ -24,6 +24,7 @@ using namespace clang::ast_matchers; namespace clang::tidy::readability { +namespace { AST_POLYMORPHIC_MATCHER(isInlineSpecified, AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, VarDecl)) { @@ -34,12 +35,26 @@ AST_POLYMORPHIC_MATCHER(isInlineSpecified, llvm_unreachable("Not a valid polymorphic type"); } -static std::optional<SourceLocation> -getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources, - const LangOptions &LangOpts) { +AST_POLYMORPHIC_MATCHER_P(isInternalLinkage, + AST_POLYMORPHIC_SUPPORTED_TYPES(FunctionDecl, + VarDecl), + bool, strictMode) { + if (!strictMode) + return false; + if (const auto *FD = dyn_cast<FunctionDecl>(&Node)) + return FD->getStorageClass() == SC_Static || FD->isInAnonymousNamespace(); + if (const auto *VD = dyn_cast<VarDecl>(&Node)) + return VD->isInAnonymousNamespace(); + llvm_unreachable("Not a valid polymorphic type"); +} +} // namespace + +static SourceLocation getInlineTokenLocation(SourceRange RangeLocation, + const SourceManager &Sources, + const LangOptions &LangOpts) { SourceLocation Loc = RangeLocation.getBegin(); if (Loc.isMacroID()) - return std::nullopt; + return {}; Token FirstToken; Lexer::getRawToken(Loc, FirstToken, Sources, LangOpts, true); @@ -53,25 +68,29 @@ getInlineTokenLocation(SourceRange RangeLocation, const SourceManager &Sources, CurrentToken = Lexer::findNextToken(CurrentToken->getLocation(), Sources, LangOpts); } - return std::nullopt; + return {}; } void RedundantInlineSpecifierCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( functionDecl(isInlineSpecified(), anyOf(isConstexpr(), isDeleted(), isDefaulted(), - isInAnonymousNamespace(), + isInternalLinkage(StrictMode), allOf(isDefinition(), hasAncestor(recordDecl())))) .bind("fun_decl"), this); - Finder->addMatcher( - functionTemplateDecl(has(functionDecl(isInlineSpecified()))) - .bind("templ_decl"), - this); + + if (StrictMode) + Finder->addMatcher( + functionTemplateDecl( + has(functionDecl(allOf(isInlineSpecified(), isDefinition())))) + .bind("templ_decl"), + this); + if (getLangOpts().CPlusPlus17) { Finder->addMatcher( varDecl(isInlineSpecified(), - anyOf(isInAnonymousNamespace(), + anyOf(isInternalLinkage(StrictMode), allOf(isConstexpr(), hasAncestor(recordDecl())))) .bind("var_decl"), this); @@ -82,10 +101,10 @@ 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())) - diag(*Loc, Message) << MatchedDecl << FixItHint::CreateRemoval(*Loc); + SourceLocation Loc = getInlineTokenLocation( + MatchedDecl->getSourceRange(), Sources, Result.Context->getLangOpts()); + if (Loc.isValid()) + diag(Loc, Message) << MatchedDecl << FixItHint::CreateRemoval(Loc); } void RedundantInlineSpecifierCheck::check( diff --git a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h index 061e6c241e6c30..cc0bfa9685d0c3 100644 --- a/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h +++ b/clang-tools-extra/clang-tidy/readability/RedundantInlineSpecifierCheck.h @@ -21,7 +21,8 @@ namespace clang::tidy::readability { class RedundantInlineSpecifierCheck : public ClangTidyCheck { public: RedundantInlineSpecifierCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + : ClangTidyCheck(Name, Context), + StrictMode(Options.getLocalOrGlobal("StrictMode", false)) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; std::optional<TraversalKind> getCheckTraversalKind() const override { @@ -33,6 +34,7 @@ class RedundantInlineSpecifierCheck : public ClangTidyCheck { void handleMatchedDecl(const T *MatchedDecl, const SourceManager &Sources, const ast_matchers::MatchFinder::MatchResult &Result, StringRef Message); + const bool StrictMode; }; } // 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 1cb20b3fdf79b7..eee324cddab481 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 @@ -22,3 +22,11 @@ functions are implicitly inlined In the example above the keyword ``inline`` is redundant since member functions defined entirely inside a class/struct/union definition are implicitly inlined. + +Options +------- + +.. option:: StrictMode + + If set to `true`, the check will also flag functions and variables that + already have internal linkage as redundant. 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 7db9b07692f47d..cdd98d8fdc20f5 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,8 +1,9 @@ -// RUN: %check_clang_tidy %s readability-redundant-inline-specifier -std=c++17 %t +// RUN: %check_clang_tidy -std=c++17 %s readability-redundant-inline-specifier %t +// RUN: %check_clang_tidy -std=c++17 -check-suffixes=,STRICT %s readability-redundant-inline-specifier %t -- -config="{CheckOptions: {readability-redundant-inline-specifier.StrictMode: 'true'}}" 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() +// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:23: warning: function 'f' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier] +// CHECK-FIXES-STRICT: template <typename T> T f() { return T{}; } @@ -12,7 +13,6 @@ template <> inline double f<double>() = delete; // 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); } @@ -30,6 +30,7 @@ class C inline C(const C&) = default; // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'C' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier] + // CHECK-FIXES: C(const C&) = default; 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] @@ -52,7 +53,6 @@ class C // 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; } @@ -61,10 +61,10 @@ constexpr inline 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] +// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:1: warning: function 'fn0' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier] +// CHECK-FIXES-STRICT: static int fn0(int i) { return i - 1; } @@ -79,7 +79,8 @@ static constexpr inline int fn1(int i) namespace { inline int fn2(int i) - // CHECK-MESSAGES: :[[@LINE-1]]:5: warning: function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:5: warning: function 'fn2' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier] + // CHECK-FIXES-STRICT: int fn2(int i) { return i - 1; } @@ -92,13 +93,13 @@ namespace } 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] + // CHECK-MESSAGES-STRICT: :[[@LINE-1]]:5: warning: variable 'MY_CONSTEXPR_VAR' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier] + // CHECK-FIXES-STRICT: constexpr int MY_CONSTEXPR_VAR = 42; } 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; } @@ -112,24 +113,19 @@ 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] +template <typename T> T fn7() { 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() +// CHECK-MESSAGES-STRICT: :[[@LINE-1]]:23: warning: function 'fn8' has inline specifier but is implicitly inlined [readability-redundant-inline-specifier] +// CHECK-FIXES-STRICT: template <typename T> T fn8() { return T{}; } _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits