Author: Tommy Chen Date: 2025-05-27T05:57:51+08:00 New Revision: 4cb25e2d37496a5f52a62a1f411a04dac20a8666
URL: https://github.com/llvm/llvm-project/commit/4cb25e2d37496a5f52a62a1f411a04dac20a8666 DIFF: https://github.com/llvm/llvm-project/commit/4cb25e2d37496a5f52a62a1f411a04dac20a8666.diff LOG: [clang-tidy] Add avoid-pragma-once. (#140388) #139618 Added: clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.h clang-tools-extra/docs/clang-tidy/checks/portability/avoid-pragma-once.rst clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib0.h clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib1.h clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib2.h clang-tools-extra/test/clang-tidy/checkers/portability/avoid-pragma-once.cpp Modified: clang-tools-extra/clang-tidy/portability/CMakeLists.txt clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp b/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp new file mode 100644 index 0000000000000..d9569d0b5c603 --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.cpp @@ -0,0 +1,47 @@ +//===--- AvoidPragmaOnceCheck.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 "AvoidPragmaOnceCheck.h" + +#include "clang/Basic/SourceManager.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/StringRef.h" + +namespace clang::tidy::portability { + +class PragmaOnceCallbacks : public PPCallbacks { +public: + PragmaOnceCallbacks(AvoidPragmaOnceCheck *Check, const SourceManager &SM) + : Check(Check), SM(SM) {} + void PragmaDirective(SourceLocation Loc, + PragmaIntroducerKind Introducer) override { + auto Str = llvm::StringRef(SM.getCharacterData(Loc)); + if (!Str.consume_front("#")) + return; + Str = Str.trim(); + if (!Str.consume_front("pragma")) + return; + Str = Str.trim(); + if (Str.starts_with("once")) + Check->diag(Loc, + "avoid 'pragma once' directive; use include guards instead"); + } + +private: + AvoidPragmaOnceCheck *Check; + const SourceManager &SM; +}; + +void AvoidPragmaOnceCheck::registerPPCallbacks(const SourceManager &SM, + Preprocessor *PP, + Preprocessor *ModuleExpanderPP) { + PP->addPPCallbacks(std::make_unique<PragmaOnceCallbacks>(this, SM)); +} + +} // namespace clang::tidy::portability diff --git a/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.h b/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.h new file mode 100644 index 0000000000000..203fdfd4bd33a --- /dev/null +++ b/clang-tools-extra/clang-tidy/portability/AvoidPragmaOnceCheck.h @@ -0,0 +1,36 @@ +//===--- AvoidPragmaOnceCheck.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_PORTABILITY_AVOIDPRAGMAONCECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPRAGMAONCECHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::portability { + +/// Finds uses of ``#pragma once`` and suggests replacing them with standard +/// include guards (``#ifndef``/``#define``/``#endif``) for improved +/// portability. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/portability/avoid-pragma-once.html +class AvoidPragmaOnceCheck : public ClangTidyCheck { +public: + AvoidPragmaOnceCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus || LangOpts.C99; + } + + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; +}; + +} // namespace clang::tidy::portability + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_PORTABILITY_AVOIDPRAGMAONCECHECK_H diff --git a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt index 5a38722a61481..73d74a550afc0 100644 --- a/clang-tools-extra/clang-tidy/portability/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/portability/CMakeLists.txt @@ -5,6 +5,7 @@ set(LLVM_LINK_COMPONENTS ) add_clang_library(clangTidyPortabilityModule STATIC + AvoidPragmaOnceCheck.cpp PortabilityTidyModule.cpp RestrictSystemIncludesCheck.cpp SIMDIntrinsicsCheck.cpp diff --git a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp index 316b98b46cf3f..a15cb36dfdaff 100644 --- a/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/portability/PortabilityTidyModule.cpp @@ -9,6 +9,7 @@ #include "../ClangTidy.h" #include "../ClangTidyModule.h" #include "../ClangTidyModuleRegistry.h" +#include "AvoidPragmaOnceCheck.h" #include "RestrictSystemIncludesCheck.h" #include "SIMDIntrinsicsCheck.h" #include "StdAllocatorConstCheck.h" @@ -20,6 +21,8 @@ namespace portability { class PortabilityModule : public ClangTidyModule { public: void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck<AvoidPragmaOnceCheck>( + "portability-avoid-pragma-once"); CheckFactories.registerCheck<RestrictSystemIncludesCheck>( "portability-restrict-system-includes"); CheckFactories.registerCheck<SIMDIntrinsicsCheck>( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 34a13149c9821..d6f2d2b37624e 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -136,6 +136,12 @@ New checks Finds unintended character output from ``unsigned char`` and ``signed char`` to an ``ostream``. +- New :doc:`portability-avoid-pragma-once + <clang-tidy/checks/portability/avoid-pragma-once>` check. + + Finds uses of ``#pragma once`` and suggests replacing them with standard + include guards (``#ifndef``/``#define``/``#endif``) for improved portability. + - New :doc:`readability-ambiguous-smartptr-reset-call <clang-tidy/checks/readability/ambiguous-smartptr-reset-call>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 1ec476eef3420..5a79d61b1fd7e 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -351,6 +351,7 @@ Clang-Tidy Checks :doc:`performance-type-promotion-in-math-fn <performance/type-promotion-in-math-fn>`, "Yes" :doc:`performance-unnecessary-copy-initialization <performance/unnecessary-copy-initialization>`, "Yes" :doc:`performance-unnecessary-value-param <performance/unnecessary-value-param>`, "Yes" + :doc:`portability-avoid-pragma-once <portability/avoid-pragma-once>`, :doc:`portability-restrict-system-includes <portability/restrict-system-includes>`, "Yes" :doc:`portability-simd-intrinsics <portability/simd-intrinsics>`, :doc:`portability-std-allocator-const <portability/std-allocator-const>`, diff --git a/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-pragma-once.rst b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-pragma-once.rst new file mode 100644 index 0000000000000..273286ae8c6b0 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/portability/avoid-pragma-once.rst @@ -0,0 +1,35 @@ +.. title:: clang-tidy - portability-avoid-pragma-once + +portability-avoid-pragma-once +============================= + +Finds uses of ``#pragma once`` and suggests replacing them with standard +include guards (``#ifndef``/``#define``/``#endif``) for improved portability. + +``#pragma once`` is a non-standard extension, despite being widely supported +by modern compilers. Relying on it can lead to portability issues in +some environments. + +Some older or specialized C/C++ compilers, particularly in embedded systems, +may not fully support ``#pragma once``. + +It can also fail in certain file system configurations, like network drives +or complex symbolic links, potentially leading to compilation issues. + +Consider the following header file: + +.. code:: c++ + + // my_header.h + #pragma once // warning: avoid 'pragma once' directive; use include guards instead + + +The warning suggests using include guards: + +.. code:: c++ + + // my_header.h + #ifndef PATH_TO_MY_HEADER_H // Good: use include guards. + #define PATH_TO_MY_HEADER_H + + #endif // PATH_TO_MY_HEADER_H diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib0.h b/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib0.h new file mode 100644 index 0000000000000..6f70f09beec22 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib0.h @@ -0,0 +1 @@ +#pragma once diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib1.h b/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib1.h new file mode 100644 index 0000000000000..bd25511851d96 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib1.h @@ -0,0 +1 @@ +# pragma once diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib2.h b/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib2.h new file mode 100644 index 0000000000000..bd47bc5c36795 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/Inputs/avoid-pragma-once/lib2.h @@ -0,0 +1 @@ +# pragma once diff --git a/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-pragma-once.cpp b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-pragma-once.cpp new file mode 100644 index 0000000000000..3fc8e8a2421eb --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/portability/avoid-pragma-once.cpp @@ -0,0 +1,15 @@ +// RUN: %check_clang_tidy %s portability-avoid-pragma-once %t \ +// RUN: -- --header-filter='.*' -- -I%S/Inputs/avoid-pragma-once + +// #pragma once +#include "lib0.h" +// CHECK-MESSAGES: lib0.h:1:1: warning: avoid 'pragma once' directive; use include guards instead + + +// # pragma once +#include "lib1.h" +// CHECK-MESSAGES: lib1.h:1:1: warning: avoid 'pragma once' directive; use include guards instead + +// # pragma once +#include "lib2.h" +// CHECK-MESSAGES: lib2.h:1:1: warning: avoid 'pragma once' directive; use include guards instead _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits