Author: Piotr Zegar Date: 2023-04-15T12:43:22Z New Revision: 9ece8753d5e6f49c31c2d988ef69225c036b25e0
URL: https://github.com/llvm/llvm-project/commit/9ece8753d5e6f49c31c2d988ef69225c036b25e0 DIFF: https://github.com/llvm/llvm-project/commit/9ece8753d5e6f49c31c2d988ef69225c036b25e0.diff LOG: [clang-tidy] Add misc-header-include-cycle check Check detects cyclic #include dependencies between user-defined headers. Reviewed By: njames93 Differential Revision: https://reviews.llvm.org/D144828 Added: clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.h clang-tools-extra/docs/clang-tidy/checks/misc/header-include-cycle.rst clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first-d.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth-d.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second-d.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-d.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-e.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-i.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-n.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-o.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third-d.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.first-s.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.fourth-s.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.second-s.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.self-s.hpp clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.third-s.hpp clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp Modified: clang-tools-extra/clang-tidy/misc/CMakeLists.txt clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp clang-tools-extra/docs/ReleaseNotes.rst clang-tools-extra/docs/clang-tidy/checks/list.rst Removed: ################################################################################ diff --git a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt index a72362906e0b..f5ffd3cddba7 100644 --- a/clang-tools-extra/clang-tidy/misc/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/misc/CMakeLists.txt @@ -19,6 +19,7 @@ add_clang_library(clangTidyMiscModule ConstCorrectnessCheck.cpp DefinitionsInHeadersCheck.cpp ConfusableIdentifierCheck.cpp + HeaderIncludeCycleCheck.cpp MiscTidyModule.cpp MisleadingBidirectional.cpp MisleadingIdentifier.cpp diff --git a/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp new file mode 100644 index 000000000000..bebd6e390ed5 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.cpp @@ -0,0 +1,180 @@ +//===--- HeaderIncludeCycleCheck.cpp - clang-tidy -------------------------===// +// +// 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 "HeaderIncludeCycleCheck.h" +#include "../utils/OptionsUtils.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/PPCallbacks.h" +#include "clang/Lex/Preprocessor.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/Support/Regex.h" +#include <algorithm> +#include <deque> +#include <optional> +#include <string> + +using namespace clang::ast_matchers; + +namespace clang::tidy::misc { + +namespace { + +struct Include { + FileID Id; + llvm::StringRef Name; + SourceLocation Loc; +}; + +class CyclicDependencyCallbacks : public PPCallbacks { +public: + CyclicDependencyCallbacks(HeaderIncludeCycleCheck &Check, + const SourceManager &SM, + const std::vector<StringRef> &IgnoredFilesList) + : Check(Check), SM(SM) { + IgnoredFilesRegexes.reserve(IgnoredFilesList.size()); + for (const StringRef &It : IgnoredFilesList) { + if (!It.empty()) + IgnoredFilesRegexes.emplace_back(It); + } + } + + void FileChanged(SourceLocation Loc, FileChangeReason Reason, + SrcMgr::CharacteristicKind FileType, + FileID PrevFID) override { + if (FileType != clang::SrcMgr::C_User) + return; + + if (Reason != EnterFile && Reason != ExitFile) + return; + + FileID Id = SM.getFileID(Loc); + if (Id.isInvalid()) + return; + + if (Reason == ExitFile) { + if ((Files.size() > 1U) && (Files.back().Id == PrevFID) && + (Files[Files.size() - 2U].Id == Id)) + Files.pop_back(); + return; + } + + if (!Files.empty() && Files.back().Id == Id) + return; + + std::optional<llvm::StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id); + llvm::StringRef FileName = + FilePath ? llvm::sys::path::filename(*FilePath) : llvm::StringRef(); + + if (!NextToEnter) + NextToEnter = Include{Id, FileName, SourceLocation()}; + + assert(NextToEnter->Name == FileName); + NextToEnter->Id = Id; + Files.emplace_back(*NextToEnter); + NextToEnter.reset(); + } + + void InclusionDirective(SourceLocation, const Token &, StringRef FilePath, + bool, CharSourceRange Range, + OptionalFileEntryRef File, StringRef, StringRef, + const Module *, + SrcMgr::CharacteristicKind FileType) override { + if (FileType != clang::SrcMgr::C_User) + return; + + llvm::StringRef FileName = llvm::sys::path::filename(FilePath); + NextToEnter = {FileID(), FileName, Range.getBegin()}; + + if (!File) + return; + + FileID Id = SM.translateFile(*File); + if (Id.isInvalid()) + return; + + checkForDoubleInclude(Id, FileName, Range.getBegin()); + } + + void EndOfMainFile() override { + if (!Files.empty() && Files.back().Id == SM.getMainFileID()) + Files.pop_back(); + + assert(Files.empty()); + } + + void checkForDoubleInclude(FileID Id, llvm::StringRef FileName, + SourceLocation Loc) { + auto It = + std::find_if(Files.rbegin(), Files.rend(), + [&](const Include &Entry) { return Entry.Id == Id; }); + if (It == Files.rend()) + return; + + const std::optional<StringRef> FilePath = SM.getNonBuiltinFilenameForID(Id); + if (!FilePath || isFileIgnored(*FilePath)) + return; + + if (It == Files.rbegin()) { + Check.diag(Loc, "direct self-inclusion of header file '%0'") << FileName; + return; + } + + Check.diag(Loc, "circular header file dependency detected while including " + "'%0', please check the include path") + << FileName; + + const bool IsIncludePathValid = + std::all_of(Files.rbegin(), It, [](const Include &Elem) { + return !Elem.Name.empty() && Elem.Loc.isValid(); + }); + + if (!IsIncludePathValid) + return; + + auto CurrentIt = Files.rbegin(); + do { + Check.diag(CurrentIt->Loc, "'%0' included from here", DiagnosticIDs::Note) + << CurrentIt->Name; + } while (CurrentIt++ != It); + } + + bool isFileIgnored(StringRef FileName) const { + return llvm::any_of(IgnoredFilesRegexes, [&](const llvm::Regex &It) { + return It.match(FileName); + }); + } + +private: + std::deque<Include> Files; + std::optional<Include> NextToEnter; + HeaderIncludeCycleCheck &Check; + const SourceManager &SM; + std::vector<llvm::Regex> IgnoredFilesRegexes; +}; + +} // namespace + +HeaderIncludeCycleCheck::HeaderIncludeCycleCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + IgnoredFilesList(utils::options::parseStringList( + Options.get("IgnoredFilesList", ""))) {} + +void HeaderIncludeCycleCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + PP->addPPCallbacks( + std::make_unique<CyclicDependencyCallbacks>(*this, SM, IgnoredFilesList)); +} + +void HeaderIncludeCycleCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "IgnoredFilesList", + utils::options::serializeStringList(IgnoredFilesList)); +} + +} // namespace clang::tidy::misc diff --git a/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.h b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.h new file mode 100644 index 000000000000..9a1a72399f42 --- /dev/null +++ b/clang-tools-extra/clang-tidy/misc/HeaderIncludeCycleCheck.h @@ -0,0 +1,34 @@ +//===--- HeaderIncludeCycleCheck.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_MISC_HEADERINCLUDECYCLECHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_HEADERINCLUDECYCLECHECK_H + +#include "../ClangTidyCheck.h" +#include <vector> + +namespace clang::tidy::misc { + +/// Check detects cyclic #include dependencies between user-defined headers. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/misc/header-include-cycle.html +class HeaderIncludeCycleCheck : public ClangTidyCheck { +public: + HeaderIncludeCycleCheck(StringRef Name, ClangTidyContext *Context); + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; + void storeOptions(ClangTidyOptions::OptionMap &Opts) override; + +private: + const std::vector<StringRef> IgnoredFilesList; +}; + +} // namespace clang::tidy::misc + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_MISC_HEADERINCLUDECYCLECHECK_H diff --git a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp index 2ec61f891263..5cac3d7e752a 100644 --- a/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/misc/MiscTidyModule.cpp @@ -12,6 +12,7 @@ #include "ConfusableIdentifierCheck.h" #include "ConstCorrectnessCheck.h" #include "DefinitionsInHeadersCheck.h" +#include "HeaderIncludeCycleCheck.h" #include "MisleadingBidirectional.h" #include "MisleadingIdentifier.h" #include "MisplacedConstCheck.h" @@ -41,6 +42,8 @@ class MiscModule : public ClangTidyModule { "misc-const-correctness"); CheckFactories.registerCheck<DefinitionsInHeadersCheck>( "misc-definitions-in-headers"); + CheckFactories.registerCheck<HeaderIncludeCycleCheck>( + "misc-header-include-cycle"); CheckFactories.registerCheck<MisleadingBidirectionalCheck>( "misc-misleading-bidirectional"); CheckFactories.registerCheck<MisleadingIdentifierCheck>( diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index 55474e1d9bd7..6b864f8b5c82 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -136,6 +136,11 @@ New checks Checks that all implicit and explicit inline functions in header files are tagged with the ``LIBC_INLINE`` macro. +- New :doc:`misc-header-include-cycle + <clang-tidy/checks/misc/header-include-cycle>` check. + + Check detects cyclic ``#include`` dependencies between user-defined headers. + - New :doc:`modernize-type-traits <clang-tidy/checks/modernize/type-traits>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index c4eaedc253f8..1c4304e0648b 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -251,6 +251,7 @@ Clang-Tidy Checks `misc-confusable-identifiers <misc/confusable-identifiers.html>`_, `misc-const-correctness <misc/const-correctness.html>`_, "Yes" `misc-definitions-in-headers <misc/definitions-in-headers.html>`_, "Yes" + `misc-header-include-cycle <misc/header-include-cycle.html>`_, `misc-misleading-bidirectional <misc/misleading-bidirectional.html>`_, `misc-misleading-identifier <misc/misleading-identifier.html>`_, `misc-misplaced-const <misc/misplaced-const.html>`_, diff --git a/clang-tools-extra/docs/clang-tidy/checks/misc/header-include-cycle.rst b/clang-tools-extra/docs/clang-tidy/checks/misc/header-include-cycle.rst new file mode 100644 index 000000000000..622dc784f3c6 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/misc/header-include-cycle.rst @@ -0,0 +1,71 @@ +.. title:: clang-tidy - misc-header-include-cycle + +misc-header-include-cycle +========================= + +Check detects cyclic ``#include`` dependencies between user-defined headers. + +.. code-block:: c++ + + // Header A.hpp + #pragma once + #include "B.hpp" + + // Header B.hpp + #pragma once + #include "C.hpp" + + // Header C.hpp + #pragma once + #include "A.hpp" + + // Include chain: A->B->C->A + +Header files are a crucial part of many C++ programs, as they provide a way to +organize declarations and definitions that are shared across multiple source +files. However, header files can also create problems when they become entangled +in complex dependency cycles. Such cycles can cause issues with compilation +times, unnecessary rebuilds, and make it harder to understand the overall +structure of the code. + +To address these issues, this check has been developed. This check is designed +to detect cyclic dependencies between header files, also known as +"include cycles". An include cycle occurs when a header file `A` includes a +header file `B`, and header file `B` (or any later included header file in the +chain) includes back header file `A`, leading to a circular dependency cycle. + +This check operates at the preprocessor level and analyzes user-defined headers +and their dependencies. It focuses specifically on detecting include cycles, +and ignores other types or function dependencies. This allows it to provide a +specialized analysis that is focused on identifying and preventing issues +related to header file organization. + +The benefits of using this check are numerous. By detecting include cycles early +in the development process, developers can identify and resolve these issues +before they become more diff icult and time-consuming to fix. This can lead to +faster compile times, improved code quality, and a more maintainable codebase +overall. Additionally, by ensuring that header files are organized in a way that +avoids cyclic dependencies, developers can make their code easier to understand +and modify over time. + +It's worth noting that this tool only analyzes user-defined headers and their +dependencies, excluding system includes such as standard library headers and +third-party library headers. System includes are usually well-designed and free +of include cycles, and ignoring them helps to focus on potential issues within +the project's own codebase. This limitation doesn't diminish the tool's ability +to detect ``#include`` cycles within the analyzed code. As with any tool, +developers should use their judgment when evaluating the warnings produced by +the check and be prepared to make exceptions or modifications to their code as +needed. + +Options +------- + +.. option:: IgnoredFilesList + + Provides a way to exclude specific files/headers from the warnings raised by + a check. This can be achieved by specifying a semicolon-separated list of + regular expressions or filenames. This option can be used as an alternative + to ``//NOLINT`` when using it is not possible. + The default value of this option is an empty string, indicating that no + files are ignored by default. diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first-d.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first-d.hpp new file mode 100644 index 000000000000..6615b451c7fe --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first-d.hpp @@ -0,0 +1,4 @@ +#ifndef FIRST +#define FIRST +#include "header-include-cycle.second-d.hpp" +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first.hpp new file mode 100644 index 000000000000..a118927647db --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.first.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.second.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth-d.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth-d.hpp new file mode 100644 index 000000000000..68e3774a6a22 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth-d.hpp @@ -0,0 +1,4 @@ +#ifndef FOURTH +#define FOURTH +#include "header-include-cycle.first-d.hpp" +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth.hpp new file mode 100644 index 000000000000..df6ec5c58920 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.fourth.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.first.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second-d.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second-d.hpp new file mode 100644 index 000000000000..80202da85618 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second-d.hpp @@ -0,0 +1,4 @@ +#ifndef SECOND +#define SECOND +#include "header-include-cycle.third-d.hpp" +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second.hpp new file mode 100644 index 000000000000..0e643fef2239 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.second.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.third.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-d.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-d.hpp new file mode 100644 index 000000000000..16a2bebe96e6 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-d.hpp @@ -0,0 +1,4 @@ +#ifndef SELF +#define SELF +#include "header-include-cycle.self-d.hpp" +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-e.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-e.hpp new file mode 100644 index 000000000000..bedbace457d1 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-e.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.self-e.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-i.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-i.hpp new file mode 100644 index 000000000000..4dabd71e0253 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-i.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.self-i.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-n.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-n.hpp new file mode 100644 index 000000000000..3c163991bb07 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-n.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.self-n.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-o.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-o.hpp new file mode 100644 index 000000000000..3c163991bb07 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self-o.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.self-n.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self.hpp new file mode 100644 index 000000000000..8bf2142b5518 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.self.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.self.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third-d.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third-d.hpp new file mode 100644 index 000000000000..e9f288a9bace --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third-d.hpp @@ -0,0 +1,4 @@ +#ifndef THIRD +#define THIRD +#include "header-include-cycle.fourth-d.hpp" +#endif diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third.hpp new file mode 100644 index 000000000000..b6130028f962 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/header-include-cycle.third.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.fourth.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.first-s.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.first-s.hpp new file mode 100644 index 000000000000..400056892a76 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.first-s.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.second-s.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.fourth-s.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.fourth-s.hpp new file mode 100644 index 000000000000..fdcf5f11d4f7 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.fourth-s.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.first-s.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.second-s.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.second-s.hpp new file mode 100644 index 000000000000..614552605c86 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.second-s.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.third-s.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.self-s.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.self-s.hpp new file mode 100644 index 000000000000..dbaf65065d24 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.self-s.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.self-s.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.third-s.hpp b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.third-s.hpp new file mode 100644 index 000000000000..66fb02af6dab --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/Inputs/system/header-include-cycle.third-s.hpp @@ -0,0 +1,2 @@ +#pragma once +#include "header-include-cycle.fourth-s.hpp" diff --git a/clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp b/clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp new file mode 100644 index 000000000000..344ab994856f --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/misc/header-include-cycle.cpp @@ -0,0 +1,58 @@ +// RUN: rm -rf %T/misc-header-include-cycle-headers +// RUN: mkdir %T/misc-header-include-cycle-headers +// RUN: cp -r %S/Inputs/header-include-cycle* %T/misc-header-include-cycle-headers/ +// RUN: mkdir %T/misc-header-include-cycle-headers/system +// RUN: cp -r %S/Inputs/system/header-include-cycle* %T/misc-header-include-cycle-headers/system +// RUN: clang-tidy %s -checks='-*,misc-header-include-cycle' -header-filter=.* \ +// RUN: -config="{CheckOptions: [{key: misc-header-include-cycle.IgnoredFilesList, value: 'header-include-cycle.self-e.hpp'}]}" \ +// RUN: -- -I%T/misc-header-include-cycle-headers -isystem %T/misc-header-include-cycle-headers/system \ +// RUN: --include %T/misc-header-include-cycle-headers/header-include-cycle.self-i.hpp | FileCheck %s \ +// RUN: -check-prefix=CHECK-MESSAGES -implicit-check-not="{{warning|error|note}}:" +// RUN: rm -rf %T/misc-header-include-cycle-headers + +#ifndef MAIN_GUARD +#define MAIN_GUARD + +#include <header-include-cycle.first-d.hpp> +// CHECK-MESSAGES: header-include-cycle.fourth-d.hpp:3:10: warning: circular header file dependency detected while including 'header-include-cycle.first-d.hpp', please check the include path [misc-header-include-cycle] +// CHECK-MESSAGES: header-include-cycle.third-d.hpp:3:10: note: 'header-include-cycle.fourth-d.hpp' included from here +// CHECK-MESSAGES: header-include-cycle.second-d.hpp:3:10: note: 'header-include-cycle.third-d.hpp' included from here +// CHECK-MESSAGES: header-include-cycle.first-d.hpp:3:10: note: 'header-include-cycle.second-d.hpp' included from here +// CHECK-MESSAGES: header-include-cycle.cpp:[[@LINE-5]]:10: note: 'header-include-cycle.first-d.hpp' included from here + +#include <header-include-cycle.first.hpp> +// CHECK-MESSAGES: header-include-cycle.fourth.hpp:2:10: warning: circular header file dependency detected while including 'header-include-cycle.first.hpp', please check the include path [misc-header-include-cycle] +// CHECK-MESSAGES: header-include-cycle.third.hpp:2:10: note: 'header-include-cycle.fourth.hpp' included from here +// CHECK-MESSAGES: header-include-cycle.second.hpp:2:10: note: 'header-include-cycle.third.hpp' included from here +// CHECK-MESSAGES: header-include-cycle.first.hpp:2:10: note: 'header-include-cycle.second.hpp' included from here +// CHECK-MESSAGES: header-include-cycle.cpp:[[@LINE-5]]:10: note: 'header-include-cycle.first.hpp' included from here + +#include <header-include-cycle.self-d.hpp> +// CHECK-MESSAGES: header-include-cycle.self-d.hpp:3:10: warning: direct self-inclusion of header file 'header-include-cycle.self-d.hpp' [misc-header-include-cycle] + +// CHECK-MESSAGES: header-include-cycle.self-i.hpp:2:10: warning: direct self-inclusion of header file 'header-include-cycle.self-i.hpp' [misc-header-include-cycle] + +#include <header-include-cycle.self-o.hpp> +// CHECK-MESSAGES: header-include-cycle.self-n.hpp:2:10: warning: direct self-inclusion of header file 'header-include-cycle.self-n.hpp' [misc-header-include-cycle] + +#include <header-include-cycle.self.hpp> +// CHECK-MESSAGES: header-include-cycle.self.hpp:2:10: warning: direct self-inclusion of header file 'header-include-cycle.self.hpp' [misc-header-include-cycle] + +// Should not warn about second include of guarded headers: +#include <header-include-cycle.first.hpp> +#include <header-include-cycle.first-d.hpp> +#include <header-include-cycle.self.hpp> +#include <header-include-cycle.self-d.hpp> +#include <header-include-cycle.self-o.hpp> +#include <header-include-cycle.self-n.hpp> + +// Should not warn about system includes +#include <header-include-cycle.first-s.hpp> +#include <header-include-cycle.self-s.hpp> + +// Should not warn about this excluded header +#include <header-include-cycle.self-e.hpp> + +#include "header-include-cycle.cpp" +// CHECK-MESSAGES: header-include-cycle.cpp:[[@LINE-1]]:10: warning: direct self-inclusion of header file 'header-include-cycle.cpp' [misc-header-include-cycle] +#endif _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits