[clang] [clang-format]: Treat #pragma once as include guard for IndentPPDirectives (PR #135443)

via cfe-commits cfe-commits at lists.llvm.org
Fri Apr 11 15:00:16 PDT 2025


https://github.com/saltyJeff updated https://github.com/llvm/llvm-project/pull/135443

>From d4e3ae0fd6a4ed8f287e9566b0c3353abae09c79 Mon Sep 17 00:00:00 2001
From: saltyJeff <saltyJeff at users.noreply.github.com>
Date: Fri, 11 Apr 2025 14:24:31 -0700
Subject: [PATCH] [clang-format]: Treat #pragma once as include guard for
 IndentPPDirectives

Summary:
This patch fixes the behavior of IndentPPDirectives so that `#pragma once`'s are treated as part of include guards, and therefore the `#define` in the guard will not be indented.

Sample:
```
    #pragma once
    #ifndef HEADER_H
    #define HEADER_H
    code();
    #endif
```

Previous formatting behavior:
```
    #pragma once
    #ifndef HEADER_H
        #define HEADER_H
    code();
    #endif
```

Patched behavior:
```
    #pragma once
    #ifndef HEADER_H
    #define HEADER_H
    code();
    #endif
```

Details:
Previously, a `#ifndef`` could only start an include guard if all the lines above it were comments.
This patch changes this check to see if all the lines above the `#ifndef`` are comments OR `#pragma once``.
---
 clang/lib/Format/UnwrappedLineParser.cpp | 11 +++++++++--
 clang/unittests/Format/FormatTest.cpp    | 12 +++++++++++-
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index 60f4f30623baa..4fd16139323ca 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1102,11 +1102,18 @@ void UnwrappedLineParser::parsePPIf(bool IfDef) {
   conditionalCompilationStart(Unreachable);
   FormatToken *IfCondition = FormatTok;
   // If there's a #ifndef on the first line, and the only lines before it are
-  // comments, it could be an include guard.
+  // comments or #pragma once, it could be an include guard.
   bool MaybeIncludeGuard = IfNDef;
   if (IncludeGuard == IG_Inited && MaybeIncludeGuard) {
     for (auto &Line : Lines) {
-      if (Line.Tokens.front().Tok->isNot(tok::comment)) {
+      bool LineIsComment = Line.Tokens.front().Tok->is(tok::comment);
+      auto TokenIterator = Line.Tokens.begin();
+      bool LineIsPragmaOnce = Line.Tokens.size() >= 3 &&
+                              TokenIterator->Tok->is(tok::hash) &&
+                              (++TokenIterator)->Tok->is(tok::pp_pragma) &&
+                              (++TokenIterator)->Tok->TokenText == "once";
+
+      if (!LineIsComment && !LineIsPragmaOnce) {
         MaybeIncludeGuard = false;
         IncludeGuard = IG_Rejected;
         break;
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index f0e67c604cc4b..2c4eb7d9d581e 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -6223,6 +6223,16 @@ TEST_F(FormatTest, IndentPreprocessorDirectives) {
                "int z;\n"
                "#endif",
                Style);
+  // Treat #pragma once as part of an include guard.
+  verifyFormat("#pragma once\n"
+               "#ifndef HEADER_H\n"
+               "#define HEADER_H\n"
+               "#ifdef NOT_GUARD\n"
+               "#  define NOT_GUARD\n"
+               "#endif\n"
+               "code();\n"
+               "#endif",
+               Style);
   // FIXME: This doesn't handle the case where there's code between the
   // #ifndef and #define but all other conditions hold. This is because when
   // the #define line is parsed, UnwrappedLineParser::Lines doesn't hold the
@@ -6239,7 +6249,7 @@ TEST_F(FormatTest, IndentPreprocessorDirectives) {
                "#endif",
                Style);
   // FIXME: This doesn't handle cases where legitimate preprocessor lines may
-  // be outside an include guard. Examples are #pragma once and
+  // be outside an include guard. Examples include
   // #pragma GCC diagnostic, or anything else that does not change the meaning
   // of the file if it's included multiple times.
   verifyFormat("#ifdef WIN32\n"



More information about the cfe-commits mailing list