KyleFromKitware updated this revision to Diff 494653.
KyleFromKitware added a comment.

Removed comma from documentation.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D142123/new/

https://reviews.llvm.org/D142123

Files:
  clang-tools-extra/clang-tidy/readability/CMakeLists.txt
  clang-tools-extra/clang-tidy/readability/PragmaOnceHeaderGuardStyle.cpp
  clang-tools-extra/clang-tidy/readability/PragmaOnceHeaderGuardStyle.h
  clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
  clang-tools-extra/docs/clang-tidy/checks/readability/header-guard.rst
  clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp

Index: clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp
+++ clang-tools-extra/unittests/clang-tidy/ReadabilityModuleTest.cpp
@@ -1,6 +1,8 @@
 #include "ClangTidyTest.h"
 #include "readability/BracesAroundStatementsCheck.h"
+#include "readability/HeaderGuardCheck.h"
 #include "readability/NamespaceCommentCheck.h"
+#include "readability/PragmaOnceHeaderGuardStyle.h"
 #include "readability/SimplifyBooleanExprCheck.h"
 #include "gtest/gtest.h"
 
@@ -513,6 +515,97 @@
                 nullptr, "input.cc", {"-Wno-error=return-type"}));
 }
 
+namespace {
+struct UsePragmaOnceCheck : readability::HeaderGuardCheck {
+  UsePragmaOnceCheck(StringRef Name, ClangTidyContext *Context)
+      : HeaderGuardCheck(Name, Context) {}
+
+  std::unique_ptr<utils::HeaderGuardStyle> createHeaderGuardStyle() override {
+    return std::make_unique<readability::PragmaOnceHeaderGuardStyle>(this);
+  }
+};
+
+std::string runPragmaOnceCheck(StringRef Code, const Twine &Filename,
+                               std::optional<StringRef> ExpectedWarning,
+                               std::map<StringRef, StringRef> PathsToContent =
+                                   std::map<StringRef, StringRef>()) {
+  std::vector<ClangTidyError> Errors;
+  std::string Result = test::runCheckOnCode<UsePragmaOnceCheck>(
+      Code, &Errors, Filename, std::string("-xc++-header"), ClangTidyOptions{},
+      std::move(PathsToContent));
+  if (Errors.size() != (size_t)ExpectedWarning.has_value())
+    return "invalid error count";
+  if (ExpectedWarning && *ExpectedWarning != Errors.back().Message.Message)
+    return "expected: '" + ExpectedWarning->str() + "', saw: '" +
+           Errors.back().Message.Message + "'";
+  return Result;
+}
+} // namespace
+
+TEST(PragmaOnceHeaderGuardStyleTest, AddPragmaOnce) {
+  EXPECT_EQ("#pragma once\n"
+            "\n"
+            "void headerGuard();\n"
+            "\n",
+            runPragmaOnceCheck("#ifndef HEADER_GUARD_H\n"
+                               "#define HEADER_GUARD_H\n"
+                               "\n"
+                               "void headerGuard();\n"
+                               "\n"
+                               "#endif // HEADER_GUARD_H\n",
+                               "header-guard.h",
+                               StringRef("use #pragma once")));
+  EXPECT_EQ("#pragma once\n"
+            "\n"
+            "void headerGuardValue();\n"
+            "\n",
+            runPragmaOnceCheck("#ifndef HEADER_GUARD_VALUE_H\n"
+                               "#define HEADER_GUARD_VALUE_H \\\n"
+                               "1\n"
+                               "\n"
+                               "void headerGuardValue();\n"
+                               "\n"
+                               "#endif\n",
+                               "header-guard-value.h",
+                               StringRef("use #pragma once")));
+  EXPECT_EQ("#if !defined(DEFINED_HEADER_GUARD_H)\n"
+            "#define DEFINED_HEADER_GUARD_H\n"
+            "\n"
+            "void definedHeaderGuard();\n"
+            "\n"
+            "#endif\n",
+            runPragmaOnceCheck("#if !defined(DEFINED_HEADER_GUARD_H)\n"
+                               "#define DEFINED_HEADER_GUARD_H\n"
+                               "\n"
+                               "void definedHeaderGuard();\n"
+                               "\n"
+                               "#endif\n",
+                               "defined-header-guard.h", std::nullopt));
+  EXPECT_EQ("#pragma once\n"
+            "\n"
+            "void pragmaOnce();\n",
+            runPragmaOnceCheck("#pragma once\n"
+                               "\n"
+                               "void pragmaOnce();\n",
+                               "pragma-once.h", std::nullopt));
+  EXPECT_EQ("#pragma once\n"
+            "\n"
+            "void both();\n"
+            "\n",
+            runPragmaOnceCheck("#ifndef BOTH_H\n"
+                               "#define BOTH_H\n"
+                               "#pragma once\n"
+                               "\n"
+                               "void both();\n"
+                               "\n"
+                               "#endif // BOTH_H\n",
+                               "both.h", StringRef("use #pragma once")));
+  EXPECT_EQ("#pragma once\n"
+            "void neither();\n",
+            runPragmaOnceCheck("void neither();\n", "neither.h",
+                               StringRef("use #pragma once")));
+}
+
 } // namespace test
 } // namespace tidy
 } // namespace clang
Index: clang-tools-extra/docs/clang-tidy/checks/readability/header-guard.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/readability/header-guard.rst
+++ clang-tools-extra/docs/clang-tidy/checks/readability/header-guard.rst
@@ -24,3 +24,8 @@
    ``llvm``
 
      Use the LLVM header guard style.
+
+   ``pragma-once``
+
+     Use ``#pragma once`` instead of macro guards. Note that ``#pragma once``
+     is not portable and may not work correctly in all cases.
Index: clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
+++ clang-tools-extra/clang-tidy/readability/ReadabilityTidyModule.cpp
@@ -33,6 +33,7 @@
 #include "MisplacedArrayIndexCheck.h"
 #include "NamedParameterCheck.h"
 #include "NonConstParameterCheck.h"
+#include "PragmaOnceHeaderGuardStyle.h"
 #include "QualifiedAutoCheck.h"
 #include "RedundantAccessSpecifiersCheck.h"
 #include "RedundantControlFlowCheck.h"
@@ -145,6 +146,11 @@
     CheckFactories.registerCheck<UseAnyOfAllOfCheck>(
         "readability-use-anyofallof");
   }
+
+  void addHeaderGuardStyleFactories(
+      utils::HeaderGuardStyleFactories &StyleFactories) override {
+    StyleFactories.registerStyle<PragmaOnceHeaderGuardStyle>("pragma-once");
+  }
 };
 
 // Register the ReadabilityModule using this statically initialized variable.
Index: clang-tools-extra/clang-tidy/readability/PragmaOnceHeaderGuardStyle.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/PragmaOnceHeaderGuardStyle.h
@@ -0,0 +1,36 @@
+//===--- PragmaOnceHeaderGuardStyle.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_READABILITY_PRAGMAONCEHEADERGUARDSTYLE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_PRAGMAONCEHEADERGUARDSTYLE_H
+
+#include "../utils/HeaderGuardStyle.h"
+
+namespace clang::tidy::readability {
+
+/// Header guard style that suggests the use of #pragma once.
+class PragmaOnceHeaderGuardStyle : public utils::HeaderGuardStyle {
+public:
+  PragmaOnceHeaderGuardStyle(HeaderGuardCheck *Check)
+      : HeaderGuardStyle(Check) {}
+
+  void onHeaderGuard(Preprocessor *PP, StringRef FileName, const FileEntry *FE,
+                     SourceLocation IfndefHash, SourceLocation Ifndef,
+                     SourceLocation IfndefToken, SourceLocation DefineHash,
+                     const Token &Define, SourceLocation EndIfHash,
+                     SourceLocation EndIf) override;
+
+  void onGuardlessHeader(
+      Preprocessor *PP, StringRef FileName, const FileEntry *FE,
+      SourceLocation StartLoc,
+      const std::vector<std::tuple<SourceLocation, Token, const MacroInfo *>>
+          &Macros) override;
+};
+} // namespace clang::tidy::readability
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_READABILITY_PRAGMAONCEHEADERGUARDSTYLE_H
Index: clang-tools-extra/clang-tidy/readability/PragmaOnceHeaderGuardStyle.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/readability/PragmaOnceHeaderGuardStyle.cpp
@@ -0,0 +1,76 @@
+//===--- PragmaOnceHeaderGuardStyle.cpp - 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "PragmaOnceHeaderGuardStyle.h"
+#include "HeaderGuardCheck.h"
+#include "clang/Lex/Preprocessor.h"
+
+namespace clang::tidy::readability {
+namespace {
+CharSourceRange goToLineEnd(Preprocessor *PP, SourceLocation StartLoc,
+                            SourceLocation EndLoc) {
+  SourceManager &SM = PP->getSourceManager();
+  FileID FID = SM.getFileID(EndLoc);
+  StringRef BufData = SM.getBufferData(FID);
+  const char *EndData = BufData.begin() + SM.getFileOffset(EndLoc);
+  Lexer Lex(EndLoc, PP->getLangOpts(), BufData.begin(), EndData, BufData.end());
+  // FIXME: this is a bit hacky to get ReadToEndOfLine work.
+  Lex.setParsingPreprocessorDirective(true);
+  Lex.ReadToEndOfLine();
+  return CharSourceRange::getCharRange(
+      StartLoc, SM.getLocForStartOfFile(FID).getLocWithOffset(
+                    Lex.getCurrentBufferOffset()));
+}
+} // namespace
+
+void PragmaOnceHeaderGuardStyle::onHeaderGuard(
+    Preprocessor *PP, StringRef FileName, const FileEntry *FE,
+    SourceLocation IfndefHash, SourceLocation Ifndef,
+    SourceLocation IfndefToken, SourceLocation DefineHash, const Token &Define,
+    SourceLocation EndIfHash, SourceLocation EndIf) {
+  if (!Ifndef.isValid())
+    return;
+
+  std::vector<FixItHint> FixIts;
+
+  HeaderSearch &HeaderInfo = PP->getHeaderSearchInfo();
+
+  HeaderFileInfo &Info = HeaderInfo.getFileInfo(FE);
+
+  CharSourceRange IfndefSrcRange = goToLineEnd(PP, IfndefHash, IfndefToken);
+  CharSourceRange DefineSrcRange =
+      goToLineEnd(PP, DefineHash, Define.getLocation());
+  CharSourceRange EndifSrcRange = goToLineEnd(PP, EndIfHash, EndIf);
+
+  if (Info.isPragmaOnce)
+    FixIts.push_back(FixItHint::CreateRemoval(IfndefSrcRange));
+  else
+    FixIts.push_back(
+        FixItHint::CreateReplacement(IfndefSrcRange, "#pragma once\n"));
+
+  FixIts.push_back(FixItHint::CreateRemoval(DefineSrcRange));
+  FixIts.push_back(FixItHint::CreateRemoval(EndifSrcRange));
+
+  Check->diag(IfndefSrcRange.getBegin(), "use #pragma once") << FixIts;
+}
+
+void PragmaOnceHeaderGuardStyle::onGuardlessHeader(
+    Preprocessor *PP, StringRef FileName, const FileEntry *FE,
+    SourceLocation StartLoc,
+    const std::vector<std::tuple<SourceLocation, Token, const MacroInfo *>>
+        &Macros) {
+  HeaderSearch &HeaderInfo = PP->getHeaderSearchInfo();
+
+  HeaderFileInfo &Info = HeaderInfo.getFileInfo(FE);
+  if (Info.isPragmaOnce)
+    return;
+
+  Check->diag(StartLoc, "use #pragma once")
+      << FixItHint::CreateInsertion(StartLoc, "#pragma once\n");
+}
+} // namespace clang::tidy::readability
Index: clang-tools-extra/clang-tidy/readability/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/readability/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/readability/CMakeLists.txt
@@ -29,6 +29,7 @@
   NamedParameterCheck.cpp
   NamespaceCommentCheck.cpp
   NonConstParameterCheck.cpp
+  PragmaOnceHeaderGuardStyle.cpp
   QualifiedAutoCheck.cpp
   ReadabilityTidyModule.cpp
   RedundantAccessSpecifiersCheck.cpp
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to