ConstCorrectnessCheck.cpp
DefinitionsInHeadersCheck.cpp
ConfusableIdentifierCheck.cpp
- HeaderIncludeCycleCheck.cpp
IncludeCleanerCheck.cpp
MiscTidyModule.cpp
MisleadingBidirectional.cpp
+++ /dev/null
-//===--- 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
+++ /dev/null
-//===--- 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
#include "ConfusableIdentifierCheck.h"
#include "ConstCorrectnessCheck.h"
#include "DefinitionsInHeadersCheck.h"
-#include "HeaderIncludeCycleCheck.h"
#include "IncludeCleanerCheck.h"
#include "MisleadingBidirectional.h"
#include "MisleadingIdentifier.h"
"misc-const-correctness");
CheckFactories.registerCheck<DefinitionsInHeadersCheck>(
"misc-definitions-in-headers");
- CheckFactories.registerCheck<HeaderIncludeCycleCheck>(
- "misc-header-include-cycle");
CheckFactories.registerCheck<IncludeCleanerCheck>("misc-include-cleaner");
CheckFactories.registerCheck<MisleadingBidirectionalCheck>(
"misc-misleading-bidirectional");
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:`misc-include-cleaner
<clang-tidy/checks/misc/include-cleaner>` check.
`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-include-cleaner <misc/include-cleaner.html>`_, "Yes"
`misc-misleading-bidirectional <misc/misleading-bidirectional.html>`_,
`misc-misleading-identifier <misc/misleading-identifier.html>`_,
+++ /dev/null
-.. 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 difficult 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.
+++ /dev/null
-#ifndef FIRST
-#define FIRST
-#include "header-include-cycle.second-d.hpp"
-#endif
+++ /dev/null
-#pragma once
-#include "header-include-cycle.second.hpp"
+++ /dev/null
-#ifndef FOURTH
-#define FOURTH
-#include "header-include-cycle.first-d.hpp"
-#endif
+++ /dev/null
-#pragma once
-#include "header-include-cycle.first.hpp"
+++ /dev/null
-#ifndef SECOND
-#define SECOND
-#include "header-include-cycle.third-d.hpp"
-#endif
+++ /dev/null
-#pragma once
-#include "header-include-cycle.third.hpp"
+++ /dev/null
-#ifndef SELF
-#define SELF
-#include "header-include-cycle.self-d.hpp"
-#endif
+++ /dev/null
-#pragma once
-#include "header-include-cycle.self-e.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.self-i.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.self-n.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.self-n.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.self.hpp"
+++ /dev/null
-#ifndef THIRD
-#define THIRD
-#include "header-include-cycle.fourth-d.hpp"
-#endif
+++ /dev/null
-#pragma once
-#include "header-include-cycle.fourth.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.second-s.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.first-s.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.third-s.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.self-s.hpp"
+++ /dev/null
-#pragma once
-#include "header-include-cycle.fourth-s.hpp"
+++ /dev/null
-// 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={{note|warning|error}}:"
-// 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: :[[@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: :[[@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: :[[@LINE-1]]:10: warning: direct self-inclusion of header file 'header-include-cycle.cpp' [misc-header-include-cycle]
-#endif