[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