[clang-tools-extra] 4cb25e2 - [clang-tidy] Add avoid-pragma-once. (#140388)

via cfe-commits cfe-commits at lists.llvm.org
Mon May 26 14:57:54 PDT 2025


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


        


More information about the cfe-commits mailing list