llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang-tools-extra @llvm/pr-subscribers-clang-tidy Author: serge-sans-paille <details> <summary>Changes</summary> --- Full diff: https://github.com/llvm/llvm-project/pull/188474.diff 8 Files Affected: - (modified) clang-tools-extra/clang-tidy/modernize/CMakeLists.txt (+1) - (modified) clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp (+2) - (added) clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.cpp (+71) - (added) clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.h (+33) - (modified) clang-tools-extra/docs/ReleaseNotes.rst (+5) - (modified) clang-tools-extra/docs/clang-tidy/checks/list.rst (+2-1) - (added) clang-tools-extra/docs/clang-tidy/checks/modernize/use-va-opt.rst (+19) - (added) clang-tools-extra/test/clang-tidy/checkers/modernize/use-va-opt.cpp (+37) ``````````diff diff --git a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt index 2c5c44db587fe..71aebcaf1feca 100644 --- a/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/modernize/CMakeLists.txt @@ -57,6 +57,7 @@ add_clang_library(clangTidyModernizeModule STATIC UseTransparentFunctorsCheck.cpp UseUncaughtExceptionsCheck.cpp UseUsingCheck.cpp + UseVaOptCheck.cpp LINK_LIBS clangTidy diff --git a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp index cc13da7535bcb..e45538213c6e7 100644 --- a/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp @@ -57,6 +57,7 @@ #include "UseTransparentFunctorsCheck.h" #include "UseUncaughtExceptionsCheck.h" #include "UseUsingCheck.h" +#include "UseVaOptCheck.h" using namespace clang::ast_matchers; @@ -145,6 +146,7 @@ class ModernizeModule : public ClangTidyModule { CheckFactories.registerCheck<UseUncaughtExceptionsCheck>( "modernize-use-uncaught-exceptions"); CheckFactories.registerCheck<UseUsingCheck>("modernize-use-using"); + CheckFactories.registerCheck<UseVaOptCheck>("modernize-use-va-opt"); } }; diff --git a/clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.cpp b/clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.cpp new file mode 100644 index 0000000000000..2ea4acf20f740 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 "UseVaOptCheck.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::modernize { + +namespace { +class VaOptPPCallbacks : public PPCallbacks { +public: + VaOptPPCallbacks(Preprocessor *PP, UseVaOptCheck *Check) + : PP(PP), Check(Check) {} + + void MacroDefined(const Token &MacroNameTok, + const MacroDirective *MD) override { + const MacroInfo *MI = MD->getMacroInfo(); + if (!MI->isVariadic()) + return; + + std::optional<Token> PrevComma; + bool PrevHashHash = false; + ; + for (Token Tok : MI->tokens()) { + if (PrevHashHash) { + if (const auto *II = Tok.getIdentifierInfo(); + II && II->getName() == "__VA_ARGS__") { + // FIXME: The replacement really should be " __VA_OPT__(,) + // __VA_ARGS__", but this breaks the fixit which removes the , in that + // case o_O. + Check->diag(Tok.getLocation(), + "Use __VA_OPT__ instead of GNU extension to __VA_ARGS__") + << FixItHint::CreateReplacement( + SourceRange(PrevComma->getLocation(), Tok.getLocation()), + " __VA_OPT__(',') __VA_ARGS__"); + } + PrevComma = std::nullopt; + PrevHashHash = false; + } else if (PrevComma) { + if (Tok.is(tok::hashhash)) + PrevHashHash = true; + else + PrevComma = std::nullopt; + } else if (Tok.is(tok::comma)) { + PrevComma = Tok; + } + } + } + +private: + Preprocessor *PP; + UseVaOptCheck *Check; +}; +} // namespace + +void UseVaOptCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, + Preprocessor *ModuleExpanderPP) { + PP->addPPCallbacks(std::make_unique<VaOptPPCallbacks>(PP, this)); +} + +} // namespace clang::tidy::modernize diff --git a/clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.h b/clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.h new file mode 100644 index 0000000000000..11493f298d842 --- /dev/null +++ b/clang-tools-extra/clang-tidy/modernize/UseVaOptCheck.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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_MODERNIZE_USEVAOPTCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEVAOPTCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::modernize { + +/// Use __VA_OPT__ instead of ##__VA_ARGS__ GNU extension. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/modernize/use-va-opt.html +class UseVaOptCheck : public ClangTidyCheck { +public: + UseVaOptCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus20 || LangOpts.C23; + } +}; + +} // namespace clang::tidy::modernize + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEVAOPTCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 49901f8a706c6..c646d5281c0b5 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -145,6 +145,11 @@ New checks Finds places where structured bindings could be used to decompose pairs and suggests replacing them. +- New :doc:`modernize-use-va-opt + <clang-tidy/checks/modernize/use-va-opt>` check. + + Use __VA_OPT__ instead of ##__VA_ARGS__ GNU extension. + - New :doc:`performance-string-view-conversions <clang-tidy/checks/performance/string-view-conversions>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index ceab1e9414951..c0f7f81c2b83a 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -241,7 +241,6 @@ Clang-Tidy Checks :doc:`google-runtime-int <google/runtime-int>`, :doc:`google-runtime-operator <google/runtime-operator>`, :doc:`google-upgrade-googletest-case <google/upgrade-googletest-case>`, "Yes" - :doc:`hicpp-exception-baseclass <hicpp/exception-baseclass>`, :doc:`hicpp-multiway-paths-covered <hicpp/multiway-paths-covered>`, :doc:`hicpp-signed-bitwise <hicpp/signed-bitwise>`, :doc:`linuxkernel-must-check-errs <linuxkernel/must-check-errs>`, @@ -328,6 +327,7 @@ Clang-Tidy Checks :doc:`modernize-use-starts-ends-with <modernize/use-starts-ends-with>`, "Yes" :doc:`modernize-use-std-bit <modernize/use-std-bit>`, "Yes" :doc:`modernize-use-std-format <modernize/use-std-format>`, "Yes" + :doc:`modernize-use-std-midway <modernize/use-std-midway>`, :doc:`modernize-use-std-numbers <modernize/use-std-numbers>`, "Yes" :doc:`modernize-use-std-print <modernize/use-std-print>`, "Yes" :doc:`modernize-use-string-view <modernize/use-string-view>`, "Yes" @@ -336,6 +336,7 @@ Clang-Tidy Checks :doc:`modernize-use-transparent-functors <modernize/use-transparent-functors>`, "Yes" :doc:`modernize-use-uncaught-exceptions <modernize/use-uncaught-exceptions>`, "Yes" :doc:`modernize-use-using <modernize/use-using>`, "Yes" + :doc:`modernize-use-va-opt <modernize/use-va-opt>`, "Yes" :doc:`mpi-buffer-deref <mpi/buffer-deref>`, "Yes" :doc:`mpi-type-mismatch <mpi/type-mismatch>`, "Yes" :doc:`objc-assert-equals <objc/assert-equals>`, "Yes" diff --git a/clang-tools-extra/docs/clang-tidy/checks/modernize/use-va-opt.rst b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-va-opt.rst new file mode 100644 index 0000000000000..af631ff18419a --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/modernize/use-va-opt.rst @@ -0,0 +1,19 @@ +.. title:: clang-tidy - modernize-use-va-opt + +modernize-use-va-opt +==================== + +Suggest using ``__VA_OPT__(,)`` instead of ``, ##__VA_ARGS__`` when implementing +variadic macro. ``, ##__VA_ARGS__`` is a GNU extension. + +.. code:: c++ + + extern int bar(...); + #define FOO(a, ...) bar(a, ##__VA_ARGS__) + +becomes: + +.. code:: c++ + + extern int bar(...); + #define FOO(a, ...) bar(a __VA_OPT__(,) __VA_ARGS__) diff --git a/clang-tools-extra/test/clang-tidy/checkers/modernize/use-va-opt.cpp b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-va-opt.cpp new file mode 100644 index 0000000000000..b0fde0000de23 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/modernize/use-va-opt.cpp @@ -0,0 +1,37 @@ +// RUN: %check_clang_tidy -std=c++20-or-later %s modernize-use-va-opt %t + +extern void foo(...); + + +// CHECK-MESSAGES: :[[@LINE+2]]:26: warning: Use __VA_OPT__ instead of GNU extension to __VA_ARGS__ [modernize-use-va-opt] +// CHECK-FIXES: #define M0(...) foo(1 __VA_OPT__(',') __VA_ARGS__) +#define M0(...) foo(1, ##__VA_ARGS__) + +// CHECK-MESSAGES: :[[@LINE+2]]:27: warning: Use __VA_OPT__ instead of GNU extension to __VA_ARGS__ [modernize-use-va-opt] +// CHECK-FIXES: #define M1(...) foo(1 __VA_OPT__(',') __VA_ARGS__) +#define M1(...) foo(1, ## __VA_ARGS__) + +// CHECK-MESSAGES: :[[@LINE+2]]:27: warning: Use __VA_OPT__ instead of GNU extension to __VA_ARGS__ [modernize-use-va-opt] +// CHECK-FIXES: #define M2(...) foo(1 __VA_OPT__(',') __VA_ARGS__) +#define M2(...) foo(1 ,## __VA_ARGS__) + +// CHECK-MESSAGES: :[[@LINE+2]]:28: warning: Use __VA_OPT__ instead of GNU extension to __VA_ARGS__ [modernize-use-va-opt] +// CHECK-FIXES: #define M3(...) foo(1 __VA_OPT__(',') __VA_ARGS__) +#define M3(...) foo(1 , ## __VA_ARGS__) + +// CHECK-MESSAGES: :[[@LINE+3]]:28: warning: Use __VA_OPT__ instead of GNU extension to __VA_ARGS__ [modernize-use-va-opt] +// CHECK-MESSAGES: :[[@LINE+2]]:44: warning: Use __VA_OPT__ instead of GNU extension to __VA_ARGS__ [modernize-use-va-opt] +// CHECK-FIXES: #define M4(...) foo(1 __VA_OPT__(',') __VA_ARGS__ __VA_OPT__(',') __VA_ARGS__) +#define M4(...) foo(1 , ## __VA_ARGS__, ## __VA_ARGS__) + +// No message, this will never add a comma before __VA_ARGS__ +#define P0(...) foo(1 ##__VA_ARGS__) + +// No message, this will never add a comma before __VA_ARGS__ +#define P1(...) foo(__VA_ARGS__) + +// No message, this will never add a comma before __VA_ARGS__ +#define P2(...) foo(##__VA_ARGS__) + +// No message, this will never add a comma before __VA_ARGS__ +#define P3(...) foo(, __VA_ARGS__) `````````` </details> https://github.com/llvm/llvm-project/pull/188474 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
