https://github.com/saltyJeff updated https://github.com/llvm/llvm-project/pull/135443
>From d4e3ae0fd6a4ed8f287e9566b0c3353abae09c79 Mon Sep 17 00:00:00 2001 From: saltyJeff <saltyj...@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" _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits