diff --git a/clang-tools-extra/clang-tidy/CMakeLists.txt b/clang-tools-extra/clang-tidy/CMakeLists.txt --- a/clang-tools-extra/clang-tidy/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/CMakeLists.txt @@ -51,6 +51,7 @@ add_subdirectory(hicpp) add_subdirectory(linuxkernel) add_subdirectory(llvm) +add_subdirectory(llvmlibc) add_subdirectory(misc) add_subdirectory(modernize) if(CLANG_ENABLE_STATIC_ANALYZER) @@ -75,6 +76,7 @@ clangTidyHICPPModule clangTidyLinuxKernelModule clangTidyLLVMModule + clangTidyLLVMLibcModule clangTidyMiscModule clangTidyModernizeModule clangTidyObjCModule diff --git a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h --- a/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h +++ b/clang-tools-extra/clang-tidy/ClangTidyForceLinker.h @@ -45,6 +45,11 @@ static int LLVM_ATTRIBUTE_UNUSED LLVMModuleAnchorDestination = LLVMModuleAnchorSource; +// This anchor is used to force the linker to link the LLVMLibcModule. +extern volatile int LLVMLibcModuleAnchorSource; +static int LLVM_ATTRIBUTE_UNUSED LLVMLibcModuleAnchorDestination = + LLVMLibcModuleAnchorSource; + // This anchor is used to force the linker to link the CppCoreGuidelinesModule. extern volatile int CppCoreGuidelinesModuleAnchorSource; static int LLVM_ATTRIBUTE_UNUSED CppCoreGuidelinesModuleAnchorDestination = diff --git a/clang-tools-extra/clang-tidy/llvmlibc/CMakeLists.txt b/clang-tools-extra/clang-tidy/llvmlibc/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvmlibc/CMakeLists.txt @@ -0,0 +1,15 @@ +set(LLVM_LINK_COMPONENTS support) + +add_clang_library(clangTidyLLVMLibcModule + LLVMLibcTidyModule.cpp + RestrictSystemLibcHeadersCheck.cpp + + LINK_LIBS + clangAST + clangASTMatchers + clangBasic + clangLex + clangTidy + clangTidyUtils + clangTooling + ) diff --git a/clang-tools-extra/clang-tidy/llvmlibc/LLVMLibcTidyModule.cpp b/clang-tools-extra/clang-tidy/llvmlibc/LLVMLibcTidyModule.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvmlibc/LLVMLibcTidyModule.cpp @@ -0,0 +1,37 @@ +//===--- LLVMLibcTidyModule.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 "../ClangTidy.h" +#include "../ClangTidyModule.h" +#include "../ClangTidyModuleRegistry.h" +#include "RestrictSystemLibcHeadersCheck.h" + +namespace clang { +namespace tidy { +namespace llvm_libc { + +class LLVMLibcModule : public ClangTidyModule { +public: + void addCheckFactories(ClangTidyCheckFactories &CheckFactories) override { + CheckFactories.registerCheck( + "llvmlibc-restrict-system-libc-headers"); + } +}; + +// Register the LLVMLibcTidyModule using this statically initialized variable. +static ClangTidyModuleRegistry::Add + X("llvmlibc-module", "Adds LLVM libc standards checks."); + +} // namespace llvm_libc + +// This anchor is used to force the linker to link in the generated object file +// and thus register the LLVMLibcModule. +volatile int LLVMLibcModuleAnchorSource = 0; + +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/clang-tidy/llvmlibc/RestrictSystemLibcHeadersCheck.h b/clang-tools-extra/clang-tidy/llvmlibc/RestrictSystemLibcHeadersCheck.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvmlibc/RestrictSystemLibcHeadersCheck.h @@ -0,0 +1,35 @@ +//===--- RestrictSystemLibcHeadersCheck.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_LLVMLIBC_RESTRICTSYSTEMLIBCHEADERSCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVMLIBC_RESTRICTSYSTEMLIBCHEADERSCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang { +namespace tidy { +namespace llvm_libc { + +/// Warns of accidental inclusions of system libc headers that aren't +/// compiler provided. +/// +/// For the user-facing documentation see: +/// http://clang.llvm.org/extra/clang-tidy/checks/llvmlibc-restrict-system-libc-headers.html +class RestrictSystemLibcHeadersCheck : public ClangTidyCheck { +public: + RestrictSystemLibcHeadersCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerPPCallbacks(const SourceManager &SM, Preprocessor *PP, + Preprocessor *ModuleExpanderPP) override; +}; + +} // namespace llvm_libc +} // namespace tidy +} // namespace clang + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_LLVMLIBC_RESTRICTSYSTEMLIBCHEADERSCHECK_H diff --git a/clang-tools-extra/clang-tidy/llvmlibc/RestrictSystemLibcHeadersCheck.cpp b/clang-tools-extra/clang-tidy/llvmlibc/RestrictSystemLibcHeadersCheck.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/clang-tidy/llvmlibc/RestrictSystemLibcHeadersCheck.cpp @@ -0,0 +1,73 @@ +//===--- RestrictSystemLibcHeadersCheck.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 "RestrictSystemLibcHeadersCheck.h" +#include "clang/AST/ASTContext.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/HeaderSearch.h" +#include "clang/Lex/HeaderSearchOptions.h" + +namespace clang { +namespace tidy { +namespace llvm_libc { + +namespace { + +class RestrictedIncludesPPCallbacks : public PPCallbacks { +public: + explicit RestrictedIncludesPPCallbacks( + RestrictSystemLibcHeadersCheck &Check, const SourceManager &SM, + const SmallString<128> CompilerIncudeDir) + : Check(Check), SM(SM), CompilerIncudeDir(CompilerIncudeDir) {} + + void InclusionDirective(SourceLocation HashLoc, const Token &IncludeTok, + StringRef FileName, bool IsAngled, + CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, + const Module *Imported, + SrcMgr::CharacteristicKind FileType) override; + +private: + RestrictSystemLibcHeadersCheck &Check; + const SourceManager &SM; + const SmallString<128> CompilerIncudeDir; +}; + +} // namespace + +void RestrictedIncludesPPCallbacks::InclusionDirective( + SourceLocation HashLoc, const Token &IncludeTok, StringRef FileName, + bool IsAngled, CharSourceRange FilenameRange, const FileEntry *File, + StringRef SearchPath, StringRef RelativePath, const Module *Imported, + SrcMgr::CharacteristicKind FileType) { + if (SrcMgr::isSystem(FileType)) { + // Compiler provided headers are allowed (e.g stddef.h). + if (SearchPath == CompilerIncudeDir) return; + if (!SM.isInMainFile(HashLoc)) { + Check.diag( + HashLoc, + "system libc header %0 not allowed, transitively included from %1") + << FileName << SM.getFilename(HashLoc); + } else { + Check.diag(HashLoc, "system libc header %0 not allowed") << FileName; + } + } +} + +void RestrictSystemLibcHeadersCheck::registerPPCallbacks( + const SourceManager &SM, Preprocessor *PP, Preprocessor *ModuleExpanderPP) { + SmallString<128> CompilerIncudeDir = + StringRef(PP->getHeaderSearchInfo().getHeaderSearchOpts().ResourceDir); + llvm::sys::path::append(CompilerIncudeDir, "include"); + PP->addPPCallbacks(std::make_unique( + *this, SM, CompilerIncudeDir)); +} + +} // namespace llvm_libc +} // namespace tidy +} // namespace clang diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -67,6 +67,12 @@ Improvements to clang-tidy -------------------------- +New module +^^^^^^^^^^ +- New module `llvmlibc`. + + This module contains checks related to the LLVM-libc coding standards. + New checks ^^^^^^^^^^ @@ -95,6 +101,12 @@ Flags use of the `C` standard library functions ``memset``, ``memcpy`` and ``memcmp`` and similar derivatives on non-trivial types. +- New :doc:`llvmlibc-restrict-system-libc-headers + ` check. + + Finds includes of system libc headers not provided by the compiler within + llvm-libc implementations. + - New :doc:`objc-dealloc-in-category ` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -187,6 +187,7 @@ `llvm-prefer-isa-or-dyn-cast-in-conditionals `_, "Yes" `llvm-prefer-register-over-unsigned `_, "Yes" `llvm-twine-local `_, "Yes" + `llvmlibc-restrict-system-libc-headers `_, `misc-definitions-in-headers `_, "Yes" `misc-misplaced-const `_, `misc-new-delete-overloads `_, diff --git a/clang-tools-extra/docs/clang-tidy/checks/llvmlibc-restrict-system-libc-headers.rst b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc-restrict-system-libc-headers.rst new file mode 100644 --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/llvmlibc-restrict-system-libc-headers.rst @@ -0,0 +1,20 @@ +.. title:: clang-tidy - llvmlibc-restrict-system-libc-headers + +llvmlibc-restrict-system-libc-headers +===================================== + +Finds includes of system libc headers not provided by the compiler within +llvm-libc implementations. + +.. code-block:: c++ + + #include // Not allowed because it is part of system libc. + #include // Allowed because it is provided by the compiler. + #include "internal/stdio.h" // Allowed because it is NOT part of system libc. + + +This check is necessary because accidentally including system libc headers can +lead to subtle and hard to detect bugs. For example consider a system libc +whose ``dirent`` struct has slightly different field ordering than llvm-libc. +While this will compile successfully, this can cause issues during runtime +because they are ABI incompatible. diff --git a/clang-tools-extra/docs/clang-tidy/index.rst b/clang-tools-extra/docs/clang-tidy/index.rst --- a/clang-tools-extra/docs/clang-tidy/index.rst +++ b/clang-tools-extra/docs/clang-tidy/index.rst @@ -68,6 +68,7 @@ ``google-`` Checks related to Google coding conventions. ``hicpp-`` Checks related to High Integrity C++ Coding Standard. ``llvm-`` Checks related to the LLVM coding conventions. +``llvmlibc-`` Checks related to the LLVM-libc coding standards. ``misc-`` Checks that we didn't have a better category for. ``modernize-`` Checks that advocate usage of modern (currently "modern" means "C++11") language constructs. diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/resource/include/stdatomic.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/resource/include/stdatomic.h new file mode 100644 diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/resource/include/stddef.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/resource/include/stddef.h new file mode 100644 diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/math.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/math.h new file mode 100644 diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/stdio.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/stdio.h new file mode 100644 diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/stdlib.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/stdlib.h new file mode 100644 diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/string.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/system/string.h new file mode 100644 diff --git a/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/transitive.h b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/transitive.h new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/Inputs/llvmlibc/transitive.h @@ -0,0 +1 @@ +#include diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers-transitive.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers-transitive.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers-transitive.cpp @@ -0,0 +1,8 @@ +// RUN: %check_clang_tidy %s llvmlibc-restrict-system-libc-headers %t \ +// RUN: -- -header-filter=.* \ +// RUN: -- -I %S/Inputs/llvmlibc \ +// RUN: -isystem %S/Inputs/llvmlibc/system \ +// RUN: -resource-dir %S/Inputs/llvmlibc/resource + +#include "transitive.h" +// CHECK-MESSAGES: :1:1: warning: system libc header math.h not allowed, transitively included from {{.*}} diff --git a/clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers.cpp b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers.cpp new file mode 100644 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/llvmlibc-restrict-system-libc-headers.cpp @@ -0,0 +1,13 @@ +// RUN: %check_clang_tidy %s llvmlibc-restrict-system-libc-headers %t \ +// RUN: -- -- -isystem %S/Inputs/llvmlibc/system \ +// RUN: -resource-dir %S/Inputs/llvmlibc/resource + +#include +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system libc header stdio.h not allowed +#include +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system libc header stdlib.h not allowed +#include "string.h" +// CHECK-MESSAGES: :[[@LINE-1]]:1: warning: system libc header string.h not allowed +#include "stdatomic.h" +#include +// Compiler provided headers should not throw warnings.