Add rules for include-what-you-use

Never wonder if you have all the right headers again!

Signed-off-by: Stephan Pleines <pleines.stephan@gmail.com>
Change-Id: I0cfc3f720f343a285d0ad59e90ec357f92547806
diff --git a/.bazelrc b/.bazelrc
index be75aa1..09c943f 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -157,6 +157,30 @@
 build:remote --remote_instance_name=fuse
 build:remote --verbose_failures
 
+# How to use IWYU - Include What You Use
+# Start by deleting any *.iwyu.txt files that you might have from a previous run:
+#  find -L bazel-bin/ -name "*.iwyu.txt" | xargs rm
+# Build desired target(s)
+#  bazel build --config=iwyu //my:target
+# run script to fix includes
+#  find -L bazel-bin/ -name "*.iwyu.txt" | \
+#  xargs -I % sh -c 'external/iwyu_prebuilt_pkg/bin/fix_includes.py --nosafe_headers < $1' sh %
+# run clang-format to get includes in the right order
+#  bazel run //tools/lint:clang_format
+# build targets, or ideally everything, to make sure that it still builds.
+#
+# If you are unhappy with the result, you have the following options:
+# Use pragmas or mappings.
+# https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUPragmas.md
+# https://github.com/include-what-you-use/include-what-you-use/blob/master/docs/IWYUMappings.md
+# Our mapping files are in tools/iwyu.
+build:iwyu --aspects @com_github_storypku_bazel_iwyu//bazel/iwyu:iwyu.bzl%iwyu_aspect
+build:iwyu --@com_github_storypku_bazel_iwyu//:iwyu_mappings=//tools/iwyu:mappings
+build:iwyu --output_groups=report
+build:iwyu --@com_github_storypku_bazel_iwyu//:iwyu_opts=--no_fwd_decls,--cxx17ns,--verbose=3
+build:iwyu --strategy=iwyu=sandboxed,standalone
+
+
 # Load a local file that users can use to customize bazel invocations.  This
 # should stay the last line in this file so users can override things when they
 # want.
diff --git a/WORKSPACE b/WORKSPACE
index 371829f..aac52f4 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -1718,3 +1718,16 @@
     strip_prefix = "expected-1.1.0",
     url = "https://github.com/TartanLlama/expected/archive/refs/tags/v1.1.0.tar.gz",
 )
+
+http_archive(
+    name = "com_github_storypku_bazel_iwyu",
+    integrity = "sha256-R/rVwWn3SveoC8lAcicw6MOfdTqLLkubpaljT4qHjJg=",
+    strip_prefix = "bazel_iwyu-bb102395e553215abd66603bcdeb6e93c66ca6d7",
+    urls = [
+        "https://github.com/storypku/bazel_iwyu/archive/bb102395e553215abd66603bcdeb6e93c66ca6d7.zip",
+    ],
+)
+
+load("@com_github_storypku_bazel_iwyu//bazel:dependencies.bzl", "bazel_iwyu_dependencies")
+
+bazel_iwyu_dependencies()
diff --git a/tools/iwyu/BUILD.bazel b/tools/iwyu/BUILD.bazel
new file mode 100644
index 0000000..957cf94
--- /dev/null
+++ b/tools/iwyu/BUILD.bazel
@@ -0,0 +1,6 @@
+filegroup(
+    name = "mappings",
+    srcs = glob([
+        "*.imp",
+    ]),
+)
diff --git a/tools/iwyu/by_hand.imp b/tools/iwyu/by_hand.imp
new file mode 100644
index 0000000..54f271b
--- /dev/null
+++ b/tools/iwyu/by_hand.imp
@@ -0,0 +1,45 @@
+[
+  # libc++ headers
+  { "include": ["<bits/chrono.h>", "private", "<chrono>", "public"] },
+  { "include": ["<bits/types/struct_sched_param.h>", "private", "<sched.h>", "public"] },
+  { "include": ["<bits/mman-map-flags-generic.h>", "private", "<sys/mman.h>", "public"] },
+  { "include": ["<bits/std_abs.h>", "private", "<cstdlib>", "public"] },
+  { "include": ["<bits/string_fortified.h>", "private", "<string.h>", "public"] },
+  { "include": ["<bits/strings_fortified.h>", "private", "<string.h>", "public"] },
+
+  # parts of Python.h
+  { "include": ["<boolobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<bytesobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<listobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<longobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<methodobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<modsupport.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<moduleobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<object.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<pyerrors.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<pymacro.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<pyport.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<tupleobject.h>", "private", "<Python.h>", "public"] },
+  { "include": ["<unicodeobject.h>", "private", "<Python.h>", "public"] },
+
+  # seasocks
+  { "include": ["<seasocks/Logger.h>", "private", "\"seasocks/Logger.h\"", "public"] },
+
+  # libjpeg
+  { "include": ["\"third_party/libjpeg/jmorecfg.h\"", "private", "\"third_party/libjpeg/jpeglib.h\"", "public"] },
+
+  # glog
+  { "include": ["\"glog/log_severity.h\"", "private", "\"glog/logging.h\"", "public"] },
+
+  # gtest
+  { "include": ["<gtest/gtest.h>", "private", "\"gtest/gtest.h\"", "public"] },
+
+  # grpc
+  { "include": ["<grpcpp/client_context.h>", "private", "\"grpcpp/client_context.h\"", "public"] },
+  { "include": ["<grpcpp/support/status.h>", "private", "\"grpcpp/support/status.h\"", "public"] },
+  { "include": ["<grpcpp/server_context.h>", "private", "\"grpcpp/server_context.h\"", "public"] },
+  { "include": ["<grpcpp/impl/service_type.h>", "private", "\"grpcpp/impl/service_type.h\"", "public"] },
+  { "include": ["<grpcpp/security/credentials.h>", "private", "\"grpcpp/security/credentials.h\"", "public"] },
+  { "include": ["<grpcpp/server.h>", "private", "\"grpcpp/server.h\"", "public"] },
+]
+
diff --git a/tools/iwyu/gtest.imp b/tools/iwyu/gtest.imp
new file mode 100644
index 0000000..60ee552
--- /dev/null
+++ b/tools/iwyu/gtest.imp
@@ -0,0 +1,14 @@
+[
+  { include: [ "@<gtest/internal/.*>",        private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "<gtest/gtest_prod.h>",        private, "\"gtest/gtest_prod.h\"", public ] },
+  { include: [ "@<gtest/gtest-.*>",           private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "@\"gtest/internal/.*\"",      private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "@\"gtest/gtest-.*\"",         private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "@<gmock/internal/.*>",        private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "@<gmock/gmock-.*>",           private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "<gmock/gmock.h>",             private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "@\"gmock/internal/.*\"",      private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "@\"gmock/gmock-.*\"",         private, "\"gmock/gmock.h\"",      public ] },
+  { include: [ "<gtest/gtest_pred_impl.h>",   private, "\"gtest/gtest.h\"",      public ] },
+  { include: [ "\"gtest/gtest_pred_impl.h\"", private, "\"gtest/gtest.h\"",      public ] },
+]
diff --git a/tools/iwyu/libcxx.imp b/tools/iwyu/libcxx.imp
new file mode 100644
index 0000000..609f4af
--- /dev/null
+++ b/tools/iwyu/libcxx.imp
@@ -0,0 +1,80 @@
+# libc++ headers
+[
+  { "include": ["<__mutex_base>", "private", "<mutex>", "public"] },
+  { "include": ["<__tree>", "private", "<set>", "public"] },
+  { "include": ["<__tree>", "private", "<map>", "public"] },
+
+  # For the following entries:
+  # cd llvm-project/libcxx/include ; find -type d -name "__*" | sort | sed -e 's#./__\(.*\)#  { "include": ["@<__\1/.*>", "private", "<\1>", "public"] },#'
+  #
+  # tweak locale_dir entry, and comment out debug_utils, fwd, pstl, support
+  { "include": ["@<__algorithm/.*>", "private", "<algorithm>", "public"] },
+  { "include": ["@<__atomic/.*>", "private", "<atomic>", "public"] },
+  { "include": ["@<__bit/.*>", "private", "<bit>", "public"] },
+  { "include": ["@<__charconv/.*>", "private", "<charconv>", "public"] },
+  { "include": ["@<__chrono/.*>", "private", "<chrono>", "public"] },
+  { "include": ["@<__compare/.*>", "private", "<compare>", "public"] },
+  { "include": ["@<__concepts/.*>", "private", "<concepts>", "public"] },
+  { "include": ["@<__condition_variable/.*>", "private", "<condition_variable>", "public"] },
+  { "include": ["@<__coroutine/.*>", "private", "<coroutine>", "public"] },
+  #{ "include": ["@<__debug_utils/.*>", "private", "<debug_utils>", "public"] },
+  { "include": ["@<__exception/.*>", "private", "<exception>", "public"] },
+  { "include": ["@<__expected/.*>", "private", "<expected>", "public"] },
+  { "include": ["@<__filesystem/.*>", "private", "<filesystem>", "public"] },
+  { "include": ["@<__format/.*>", "private", "<format>", "public"] },
+  { "include": ["@<__functional/.*>", "private", "<functional>", "public"] },
+  #{ "include": ["@<__fwd/.*>", "private", "<fwd>", "public"] },
+  { "include": ["@<__ios/.*>", "private", "<ios>", "public"] },
+  { "include": ["@<__iterator/.*>", "private", "<iterator>", "public"] },
+  { "include": ["@<__locale_dir/.*>", "private", "<locale>", "public"] },
+  { "include": ["@<__mdspan/.*>", "private", "<mdspan>", "public"] },
+  { "include": ["@<__memory/.*>", "private", "<memory>", "public"] },
+  { "include": ["@<__memory_resource/.*>", "private", "<memory_resource>", "public"] },
+  { "include": ["@<__mutex/.*>", "private", "<mutex>", "public"] },
+  { "include": ["@<__numeric/.*>", "private", "<numeric>", "public"] },
+  #{ "include": ["@<__pstl/.*>", "private", "<pstl>", "public"] },
+  { "include": ["@<__random/.*>", "private", "<random>", "public"] },
+  { "include": ["@<__ranges/.*>", "private", "<ranges>", "public"] },
+  { "include": ["@<__stop_token/.*>", "private", "<stop_token>", "public"] },
+  { "include": ["@<__string/.*>", "private", "<string>", "public"] },
+  #{ "include": ["@<__support/.*>", "private", "<support>", "public"] },
+  { "include": ["@<__system_error/.*>", "private", "<system_error>", "public"] },
+  { "include": ["@<__thread/.*>", "private", "<thread>", "public"] },
+  { "include": ["@<__tuple/.*>", "private", "<tuple>", "public"] },
+  { "include": ["@<__type_traits/.*>", "private", "<type_traits>", "public"] },
+  { "include": ["@<__utility/.*>", "private", "<utility>", "public"] },
+  { "include": ["@<__variant/.*>", "private", "<variant>", "public"] },
+
+  # For the following entries:
+  # cd llvm-project/libcxx/include ; find __fwd -type f -name "*.h" | sort | sed -e 's#__fwd/\(.*\).h#  { "include": ["<__fwd/\1.h>", "private", "<\1>", "public"] },#'
+  #
+  # tweak hash, pair, subrange entries, and comment out bit_reference, get
+  { "include": ["<__fwd/array.h>", "private", "<array>", "public"] },
+  #{ "include": ["<__fwd/bit_reference.h>", "private", "<bit_reference>", "public"] },
+  { "include": ["<__fwd/fstream.h>", "private", "<fstream>", "public"] },
+  #{ "include": ["<__fwd/get.h>", "private", "<get>", "public"] },
+  { "include": ["<__fwd/hash.h>", "private", "<functional>", "public"] },
+  { "include": ["<__fwd/ios.h>", "private", "<ios>", "public"] },
+  { "include": ["<__fwd/istream.h>", "private", "<istream>", "public"] },
+  { "include": ["<__fwd/mdspan.h>", "private", "<mdspan>", "public"] },
+  { "include": ["<__fwd/memory_resource.h>", "private", "<memory_resource>", "public"] },
+  { "include": ["<__fwd/ostream.h>", "private", "<ostream>", "public"] },
+  { "include": ["<__fwd/pair.h>", "private", "<utility>", "public"] },
+  { "include": ["<__fwd/span.h>", "private", "<span>", "public"] },
+  { "include": ["<__fwd/sstream.h>", "private", "<sstream>", "public"] },
+  { "include": ["<__fwd/streambuf.h>", "private", "<streambuf>", "public"] },
+  { "include": ["<__fwd/string.h>", "private", "<string>", "public"] },
+  { "include": ["<__fwd/string_view.h>", "private", "<string_view>", "public"] },
+  { "include": ["<__fwd/subrange.h>", "private", "<ranges>", "public"] },
+  { "include": ["<__fwd/tuple.h>", "private", "<tuple>", "public"] },
+
+  { "symbol": [ "std::nullptr_t", "private", "<cstddef>", "public"] },
+
+  # For older MacOS libc++ (13.0.0), on macOS Ventura (13.2.1)
+  { "include": ["<__functional_base>", "private", "<functional>", "public"] },
+
+  # For older libc++ (16.x)
+  { "include": ["@<__tuple_dir/.*>", "private", "<tuple>", "public"] },
+
+  { "symbol": [ "std::string", "private", "<string>", "public"] },
+]