-
Notifications
You must be signed in to change notification settings - Fork 14.4k
Add clang tidy check performance constexpr non static in scope #147809
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
//===--- ConstexprNonStaticInScopeCheck.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 "ConstexprNonStaticInScopeCheck.h" | ||
#include "clang/ASTMatchers/ASTMatchFinder.h" | ||
|
||
using namespace clang::ast_matchers; | ||
|
||
namespace clang::tidy::performance { | ||
|
||
void ConstexprNonStaticInScopeCheck::registerMatchers(MatchFinder *Finder) { | ||
Finder->addMatcher(varDecl( | ||
hasLocalStorage(), | ||
isConstexpr(), | ||
unless(isStaticLocal()) | ||
).bind("constexprVar"), this); | ||
} | ||
|
||
void ConstexprNonStaticInScopeCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { | ||
Options.store(Opts, "WarnInConstexprFuncCpp23", WarnInConstexprFuncCpp23); | ||
} | ||
|
||
void ConstexprNonStaticInScopeCheck::check(const MatchFinder::MatchResult &Result) { | ||
const auto *Var = Result.Nodes.getNodeAs<clang::VarDecl>("constexprVar"); | ||
if (!Var) | ||
return; | ||
const auto *EnclosingFunc = llvm::dyn_cast_or_null<clang::FunctionDecl>(Var->getDeclContext()); | ||
|
||
if (EnclosingFunc && EnclosingFunc->isConstexpr()) { | ||
// If the function is constexpr, only warn in C++23 and above | ||
if (!Result.Context->getLangOpts().CPlusPlus23 || !WarnInConstexprFuncCpp23) | ||
return; // Don't warn unless in C++23+ AND the option is enabled | ||
} | ||
Comment on lines
+32
to
+38
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This logic should be put directly inside ASTMatchers, try writing something like: // previous code
unless(isStaticLocal()),
(!WarnInConstexprFuncCpp23 && !getLangOpts().CPlusPlus23) ?
unless(hasParent(functionDecl(isConstexpr()))) :
anything() |
||
|
||
diag(Var->getLocation(), | ||
"constexpr variable in function scope should be static to ensure static lifetime") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "static to ensure static lifetime" seems repetitive and not the main reason why the check exists. |
||
<< FixItHint::CreateInsertion(Var->getSourceRange().getBegin(), "static "); | ||
} | ||
|
||
} // namespace clang::tidy::performance |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,37 @@ | ||||||
//===--- ConstexprNonStaticInScopeCheck.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_PERFORMANCE_CONSTEXPRNONSTATICINSCOPECHECK_H | ||||||
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_CONSTEXPRNONSTATICINSCOPECHECK_H | ||||||
|
||||||
#include "../ClangTidyCheck.h" | ||||||
|
||||||
namespace clang::tidy::performance { | ||||||
|
||||||
/// FIXME: Write a short description. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please put here description as first sentence in docs |
||||||
/// | ||||||
/// For the user-facing documentation see: | ||||||
/// http://clang.llvm.org/extra/clang-tidy/checks/performance/constexpr-non-static-in-scope.html | ||||||
class ConstexprNonStaticInScopeCheck : public ClangTidyCheck { | ||||||
public: | ||||||
ConstexprNonStaticInScopeCheck(StringRef Name, ClangTidyContext *Context) | ||||||
: ClangTidyCheck(Name, Context), | ||||||
WarnInConstexprFuncCpp23(Options.get("WarnInConstexprFuncCpp23", /*Default=*/true)) {} | ||||||
void registerMatchers(ast_matchers::MatchFinder *Finder) override; | ||||||
void check(const ast_matchers::MatchFinder::MatchResult &Result) override; | ||||||
bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { | ||||||
return LangOpts.CPlusPlus; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
} | ||||||
void storeOptions(ClangTidyOptions::OptionMap &Opts) override; | ||||||
private: | ||||||
const bool WarnInConstexprFuncCpp23; | ||||||
}; | ||||||
|
||||||
} // namespace clang::tidy::performance | ||||||
|
||||||
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PERFORMANCE_CONSTEXPRNONSTATICINSCOPECHECK_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -148,6 +148,11 @@ New checks | |
Finds uses of ``std::lock_guard`` and suggests replacing them with C++17's | ||
alternative ``std::scoped_lock``. | ||
|
||
- New :doc:`performance-constexpr-non-static-in-scope | ||
<clang-tidy/checks/performance/constexpr-non-static-in-scope>` check. | ||
|
||
FIXME: Write a short description. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add description (should be same as first sentence in docs) |
||
|
||
- New :doc:`portability-avoid-pragma-once | ||
<clang-tidy/checks/portability/avoid-pragma-once>` check. | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,42 @@ | ||||||||
.. title:: clang-tidy - performance-constexpr-non-static-in-scope | ||||||||
|
||||||||
performance-constexpr-non-static-in-scope | ||||||||
========================================= | ||||||||
|
||||||||
The check ``performance-constexpr-non-static-in-scope`` identifies ``constexpr`` variables declared in function (local) scope that are not marked ``static``. In most cases, such variables should be declared `static constexpr` to avoid creating a new instance on every function call. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please follow 80-character limit and dont use "the check" or its name. |
||||||||
|
||||||||
The check will always warn for non-static ``constexpr`` variables in non-constexpr functions. For ``constexpr`` functions, the check warns only in C++23 and newer (and this behavior can be controlled with the ``WarnInConstexprFuncCpp23`` option). | ||||||||
|
||||||||
For example: | ||||||||
When a ``constexpr` ` is declared without ``static``: | ||||||||
Comment on lines
+10
to
+11
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||
.. code-block:: c++ | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please make a newline between text and code-block |
||||||||
// BEFORE | ||||||||
void foo() { | ||||||||
constexpr int x = 42; | ||||||||
} | ||||||||
|
||||||||
// AFTER | ||||||||
void foo() { | ||||||||
static constexpr int x = 42; // Corrected to static constexpr | ||||||||
} | ||||||||
|
||||||||
When a ``constexpr`` is declared in a ``constexpr`` function without ``static`` (only in C++23 and newer): | ||||||||
.. code-block:: c++ | ||||||||
// BEFORE | ||||||||
constexpr int bar() { | ||||||||
constexpr int y = 123; | ||||||||
return y; | ||||||||
} | ||||||||
|
||||||||
// AFTER | ||||||||
constexpr int bar() { | ||||||||
static constexpr int y = 123; // Corrected to static constexpr | ||||||||
return y; | ||||||||
} | ||||||||
|
||||||||
Options | ||||||||
------- | ||||||||
|
||||||||
.. option:: WarnInConstexprFuncCpp23 | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we should have name |
||||||||
|
||||||||
When true (default), warns on ``constexpr`` variables inside ``constexpr`` functions in C++23 and newer. Set to ``false`` to disable this warning in that scenario. | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please write about default value at the end: "Default is `false`" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// RUN: %check_clang_tidy %s performance-constexpr-non-static-in-scope %t -- -- -std=c++23 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Write 2 RUN commands in this test file. One for default value of option, another with There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add tests with
|
||
|
||
// This should trigger the check (constexpr local, not static). | ||
void f() { | ||
constexpr int x = 42; | ||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constexpr variable in function scope should be static to ensure static lifetime [performance-constexpr-non-static-in-scope] | ||
// CHECK-FIXES: static constexpr int x = 42; | ||
} | ||
|
||
// This should trigger if WarnInConstexprFuncCpp23 is true and C++23 or newer. | ||
constexpr int g() { | ||
constexpr int y = 123; | ||
// CHECK-MESSAGES: :[[@LINE-1]]:3: warning: constexpr variable in function scope should be static to ensure static lifetime [performance-constexpr-non-static-in-scope] | ||
// CHECK-FIXES: static constexpr int y = 123; | ||
return y; | ||
} | ||
|
||
// This should NOT trigger the check (already static). | ||
void h() { | ||
static constexpr int z = 99; | ||
} | ||
|
||
// This should NOT trigger the check (not constexpr). | ||
void i() { | ||
int w = 100; | ||
} | ||
|
||
// This should NOT trigger the check (not declared inside a function) | ||
namespace ns { | ||
inline constexpr int MAX_SIZE = 1024; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add newline |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should write
assert(Var);
, "constexprVar" should always be valid.