KyleFromKitware created this revision.
KyleFromKitware added a reviewer: clang-tools-extra.
KyleFromKitware created this object with edit policy "Only User:
KyleFromKitware (Kyle Edwards)".
KyleFromKitware added a project: clang-tools-extra.
Herald added subscribers: carlosgalvezp, xazax.hun.
Herald added a reviewer: njames93.
Herald added a project: All.
KyleFromKitware requested review of this revision.
Herald added a subscriber: cfe-commits.
Co-Authored-by: Igor-Mikhail-Valentin Glebov <[email protected]>
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D142123
Files:
clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
clang-tools-extra/clang-tidy/modernize/UsePragmaOnceCheck.cpp
clang-tools-extra/clang-tidy/modernize/UsePragmaOnceCheck.h
clang-tools-extra/unittests/clang-tidy/ModernizeModuleTest.cpp
Index: clang-tools-extra/unittests/clang-tidy/ModernizeModuleTest.cpp
===================================================================
--- clang-tools-extra/unittests/clang-tidy/ModernizeModuleTest.cpp
+++ clang-tools-extra/unittests/clang-tidy/ModernizeModuleTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "ClangTidyTest.h"
#include "modernize/IntegralLiteralExpressionMatcher.h"
+#include "modernize/UsePragmaOnceCheck.h"
#include "clang/Lex/Lexer.h"
#include "gtest/gtest.h"
@@ -272,6 +273,62 @@
INSTANTIATE_TEST_SUITE_P(IntegralLiteralExpressionMatcherTests, SizeTest,
::testing::ValuesIn(SizeParams));
+namespace {
+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<modernize::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(UsePragmaOnceCheckTest, 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/clang-tidy/modernize/UsePragmaOnceCheck.h
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/modernize/UsePragmaOnceCheck.h
@@ -0,0 +1,47 @@
+//===--- UsePragmaOnceCheck.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_MODERNIZE_USEPRAGMAONCECHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEPRAGMAONCECHECK_H
+
+#include "../utils/HeaderGuardBase.h"
+
+namespace clang {
+namespace tidy {
+namespace modernize {
+
+/// Check that suggests the use of #pragma once.
+/// The check supports these options:
+/// - `HeaderFileExtensions`: a semicolon-separated list of filename
+/// extensions of header files (The filename extension should not contain
+/// "." prefix). ";h;hh;hpp;hxx" by default.
+///
+/// For extension-less header files, using an empty string or leaving an
+/// empty string between ";" if there are other filename extensions.
+class UsePragmaOnceCheck : public utils::HeaderGuardBase {
+public:
+ UsePragmaOnceCheck(StringRef Name, ClangTidyContext *Context)
+ : HeaderGuardBase(Name, Context) {}
+
+ 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 modernize
+} // namespace tidy
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MODERNIZE_USEPRAGMAONCECHECK_H
Index: clang-tools-extra/clang-tidy/modernize/UsePragmaOnceCheck.cpp
===================================================================
--- /dev/null
+++ clang-tools-extra/clang-tidy/modernize/UsePragmaOnceCheck.cpp
@@ -0,0 +1,72 @@
+//===--- 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 "UsePragmaOnceCheck.h"
+#include "clang/Lex/Preprocessor.h"
+
+namespace clang::tidy::modernize {
+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 UsePragmaOnceCheck::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));
+
+ diag(IfndefSrcRange.getBegin(), "use #pragma once") << FixIts;
+}
+
+void UsePragmaOnceCheck::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;
+
+ diag(StartLoc, "use #pragma once")
+ << FixItHint::CreateInsertion(StartLoc, "#pragma once\n");
+}
+} // namespace clang::tidy::modernize
Index: clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
===================================================================
--- clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
+++ clang-tools-extra/clang-tidy/modernize/ModernizeTidyModule.cpp
@@ -37,6 +37,7 @@
#include "UseNoexceptCheck.h"
#include "UseNullptrCheck.h"
#include "UseOverrideCheck.h"
+#include "UsePragmaOnceCheck.h"
#include "UseTrailingReturnTypeCheck.h"
#include "UseTransparentFunctorsCheck.h"
#include "UseUncaughtExceptionsCheck.h"
@@ -92,6 +93,8 @@
CheckFactories.registerCheck<UseNoexceptCheck>("modernize-use-noexcept");
CheckFactories.registerCheck<UseNullptrCheck>("modernize-use-nullptr");
CheckFactories.registerCheck<UseOverrideCheck>("modernize-use-override");
+ CheckFactories.registerCheck<UsePragmaOnceCheck>(
+ "modernize-use-pragma-once");
CheckFactories.registerCheck<UseTrailingReturnTypeCheck>(
"modernize-use-trailing-return-type");
CheckFactories.registerCheck<UseTransparentFunctorsCheck>(
Index: clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
===================================================================
--- clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
+++ clang-tools-extra/clang-tidy/modernize/CMakeLists.txt
@@ -36,6 +36,7 @@
UseNoexceptCheck.cpp
UseNullptrCheck.cpp
UseOverrideCheck.cpp
+ UsePragmaOnceCheck.cpp
UseTrailingReturnTypeCheck.cpp
UseTransparentFunctorsCheck.cpp
UseUncaughtExceptionsCheck.cpp
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits