KyleFromKitware updated this revision to Diff 492579.
KyleFromKitware retitled this revision from "[clang-tidy] Add check to suggest 
use of #pragma once" to "[clang-tidy] Add header guard style to suggest use of 
#pragma once".
KyleFromKitware added a comment.

Refactored to use HeaderGuardStyle.


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/list.rst
  clang-tools-extra/docs/clang-tidy/checks/modernize/use-pragma-once.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,71 @@
                 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 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/modernize/use-pragma-once.rst
===================================================================
--- /dev/null
+++ clang-tools-extra/docs/clang-tidy/checks/modernize/use-pragma-once.rst
@@ -0,0 +1,22 @@
+.. title:: clang-tidy - modernize-use-pragma-once
+
+modernize-use-pragma-once
+=========================
+
+Adds ``#pragma once`` (a widely-supported compiler extension) to header files
+and removes header guards if they are used (``#ifndef`` / ``#define`` /
+``#endif``).
+
+Note that ``#pragma once`` cannot be correct in all possible use cases and has
+not been added to the C++ standard. Not all projects will wish to use it.
+
+Options
+-------
+
+.. option:: HeaderFileExtensions
+
+   A comma-separated list of filename extensions of header files (the filename
+   extensions should not include "." prefix). Default is "h,hh,hpp,hxx".
+   For header files without an extension, use an empty string (if there are no
+   other desired extensions) or leave an empty element in the list. E.g.,
+   "h,hh,hpp,hxx," (note the trailing comma).
Index: clang-tools-extra/docs/clang-tidy/checks/list.rst
===================================================================
--- clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -290,6 +290,7 @@
    `modernize-use-noexcept <modernize/use-noexcept.html>`_, "Yes"
    `modernize-use-nullptr <modernize/use-nullptr.html>`_, "Yes"
    `modernize-use-override <modernize/use-override.html>`_, "Yes"
+   `modernize-use-pragma-once <modernize/use-pragma-once.html>`_, "Yes"
    `modernize-use-trailing-return-type <modernize/use-trailing-return-type.html>`_, "Yes"
    `modernize-use-transparent-functors <modernize/use-transparent-functors.html>`_, "Yes"
    `modernize-use-uncaught-exceptions <modernize/use-uncaught-exceptions.html>`_, "Yes"
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,73 @@
+//===--- UsePragmaOnceCheck.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) {
+  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