1821 lines
86 KiB
C++
1821 lines
86 KiB
C++
//===--- iwyu_include_picker.cc - map to canonical #includes for iwyu -----===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "iwyu_include_picker.h"
|
|
|
|
#include <algorithm> // for find
|
|
#include <cstddef> // for size_t
|
|
// TODO(wan): make sure IWYU doesn't suggest <iterator>.
|
|
#include <iterator> // for find
|
|
// not hash_map: it's not as portable and needs hash<string>.
|
|
#include <map> // for map, map<>::mapped_type, etc
|
|
#include <memory>
|
|
#include <string> // for string, basic_string, etc
|
|
#include <system_error> // for error_code
|
|
#include <utility> // for pair, make_pair
|
|
#include <vector> // for vector, vector<>::iterator
|
|
|
|
#include "iwyu_location_util.h"
|
|
#include "iwyu_path_util.h"
|
|
#include "iwyu_port.h"
|
|
#include "iwyu_regex.h"
|
|
#include "iwyu_stl_util.h"
|
|
#include "iwyu_string_util.h"
|
|
#include "iwyu_verrs.h"
|
|
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include "llvm/Support/Casting.h"
|
|
#include "llvm/Support/ErrorOr.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/SourceMgr.h"
|
|
#include "llvm/Support/YAMLParser.h"
|
|
#include "clang/Basic/FileManager.h"
|
|
|
|
using std::find;
|
|
using std::make_pair;
|
|
using std::map;
|
|
using std::pair;
|
|
using std::string;
|
|
using std::unique_ptr;
|
|
using std::vector;
|
|
|
|
using llvm::MemoryBuffer;
|
|
using llvm::SourceMgr;
|
|
using llvm::yaml::KeyValueNode;
|
|
using llvm::yaml::MappingNode;
|
|
using llvm::yaml::Node;
|
|
using llvm::yaml::ScalarNode;
|
|
using llvm::yaml::SequenceNode;
|
|
using llvm::yaml::Stream;
|
|
using llvm::yaml::document_iterator;
|
|
|
|
namespace include_what_you_use {
|
|
|
|
// If we map from A to B, it means that every time we need a
|
|
// symbol from A, we can also get it from B. Another way
|
|
// to think about it is that map_to "re-exports" all the
|
|
// symbols from map_from.
|
|
struct IncludeMapEntry { // A POD so we can make the input static
|
|
const char* map_from; // A quoted-include or a symbol name
|
|
IncludeVisibility from_visibility;
|
|
const char* map_to; // A quoted-include
|
|
IncludeVisibility to_visibility;
|
|
};
|
|
|
|
namespace {
|
|
|
|
// Listed below are all IWYU's native symbol and include mappings,
|
|
// loosely based on GCC 4.4's libc and libstdc++.
|
|
|
|
// Symbol -> include mappings for GNU libc
|
|
const IncludeMapEntry libc_symbol_map[] = {
|
|
// For library symbols that can be defined in more than one header
|
|
// file, maps from symbol-name to legitimate header files.
|
|
// This list was generated via
|
|
// grep -R '__.*_defined' /usr/include | perl -nle 'm,/usr/include/([^:]*):#\s*\S+ __(.*)_defined, and print qq@ { "$2", kPublic, "<$1>", kPublic },@' | sort -u
|
|
// I ignored all entries that only appeared once on the list (eg uint32_t).
|
|
// I then added in NULL, which according to [diff.null] C.2.2.3, can
|
|
// be defined in <clocale>, <cstddef>, <cstdio>, <cstdlib>,
|
|
// <cstring>, <ctime>, or <cwchar>. We also allow their C
|
|
// equivalents.
|
|
// In each case, I ordered them so <sys/types.h> was first, if it was
|
|
// an option for this type. That's the preferred #include all else
|
|
// equal. The visibility on the symbol-name is ignored; by convention
|
|
// we always set it to kPrivate.
|
|
{ "aiocb", kPrivate, "<aio.h>", kPublic },
|
|
{ "blkcnt_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "blkcnt_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "blksize_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "blksize_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "cc_t", kPrivate, "<termios.h>", kPublic },
|
|
{ "clock_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "clock_t", kPrivate, "<sys/time.h>", kPublic },
|
|
{ "clock_t", kPrivate, "<time.h>", kPublic },
|
|
{ "clockid_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "clockid_t", kPrivate, "<time.h>", kPublic },
|
|
{ "daddr_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "daddr_t", kPrivate, "<rpc/types.h>", kPublic },
|
|
{ "dev_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "dev_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "div_t", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "double_t", kPrivate, "<math.h>", kPublic },
|
|
{ "error_t", kPrivate, "<errno.h>", kPublic },
|
|
{ "error_t", kPrivate, "<argp.h>", kPublic },
|
|
{ "error_t", kPrivate, "<argz.h>", kPublic },
|
|
{ "fd_set", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "fd_set", kPrivate, "<sys/time.h>", kPublic },
|
|
{ "fenv_t", kPrivate, "<fenv.h>", kPublic },
|
|
{ "fexcept_t", kPrivate, "<fenv.h>", kPublic },
|
|
{ "FILE", kPrivate, "<stdio.h>", kPublic },
|
|
{ "FILE", kPrivate, "<wchar.h>", kPublic },
|
|
{ "float_t", kPrivate, "<math.h>", kPublic },
|
|
{ "fsblkcnt_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "fsblkcnt_t", kPrivate, "<sys/statvfs.h>", kPublic },
|
|
{ "fsfilcnt_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "fsfilcnt_t", kPrivate, "<sys/statvfs.h>", kPublic },
|
|
{ "getopt", kPrivate, "<unistd.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<grp.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<pwd.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<signal.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<stropts.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "gid_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "htonl", kPrivate, "<arpa/inet.h>", kPublic },
|
|
{ "htons", kPrivate, "<arpa/inet.h>", kPublic },
|
|
{ "id_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "id_t", kPrivate, "<sys/resource.h>", kPublic },
|
|
{ "imaxdiv_t", kPrivate, "<inttypes.h>", kPublic },
|
|
{ "intmax_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "uintmax_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "ino64_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "ino64_t", kPrivate, "<dirent.h>", kPublic },
|
|
{ "ino_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "ino_t", kPrivate, "<dirent.h>", kPublic },
|
|
{ "ino_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "int8_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "int16_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "int32_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "int64_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "uint8_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "uint16_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "uint32_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "uint64_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "intptr_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "uintptr_t", kPrivate, "<stdint.h>", kPublic },
|
|
{ "iovec", kPrivate, "<sys/uio.h>", kPublic },
|
|
{ "iovec", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "itimerspec", kPrivate, "<time.h>", kPublic },
|
|
{ "itimerspec", kPrivate, "<sys/timerfd.h>", kPublic },
|
|
{ "key_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "key_t", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "lconv", kPrivate, "<locale.h>", kPublic },
|
|
{ "ldiv_t", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "lldiv_t", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "max_align_t", kPrivate, "<stddef.h>", kPublic },
|
|
{ "mode_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "mode_t", kPrivate, "<fcntl.h>", kPublic },
|
|
{ "mode_t", kPrivate, "<ndbm.h>", kPublic },
|
|
{ "mode_t", kPrivate, "<spawn.h>", kPublic },
|
|
{ "mode_t", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "mode_t", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "mode_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "nlink_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "nlink_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "ntohl", kPrivate, "<arpa/inet.h>", kPublic },
|
|
{ "ntohs", kPrivate, "<arpa/inet.h>", kPublic },
|
|
{ "off64_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "off64_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "off_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "off_t", kPrivate, "<aio.h>", kPublic },
|
|
{ "off_t", kPrivate, "<fcntl.h>", kPublic },
|
|
{ "off_t", kPrivate, "<stdio.h>", kPublic },
|
|
{ "off_t", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "off_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "off_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "optarg", kPrivate, "<unistd.h>", kPublic },
|
|
{ "opterr", kPrivate, "<unistd.h>", kPublic },
|
|
{ "optind", kPrivate, "<unistd.h>", kPublic },
|
|
{ "optopt", kPrivate, "<unistd.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<fcntl.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<sched.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<signal.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<spawn.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<sys/msg.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<sys/sem.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<sys/shm.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<sys/wait.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<termios.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<time.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "pid_t", kPrivate, "<utmpx.h>", kPublic },
|
|
{ "ptrdiff_t", kPrivate, "<stddef.h>", kPublic },
|
|
{ "regex_t", kPrivate, "<regex.h>", kPublic },
|
|
{ "regmatch_t", kPrivate, "<regex.h>", kPublic },
|
|
{ "regoff_t", kPrivate, "<regex.h>", kPublic },
|
|
{ "sigevent", kPrivate, "<signal.h>", kPublic },
|
|
{ "sigevent", kPrivate, "<aio.h>", kPublic },
|
|
{ "sigevent", kPrivate, "<mqueue.h>", kPublic },
|
|
{ "sigevent", kPrivate, "<time.h>", kPublic },
|
|
{ "siginfo_t", kPrivate, "<signal.h>", kPublic },
|
|
{ "siginfo_t", kPrivate, "<sys/wait.h>", kPublic },
|
|
{ "sigset_t", kPrivate, "<signal.h>", kPublic },
|
|
{ "sigset_t", kPrivate, "<spawn.h>", kPublic },
|
|
{ "sigset_t", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "sigval", kPrivate, "<signal.h>", kPublic },
|
|
{ "sockaddr", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "socklen_t", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "socklen_t", kPrivate, "<netdb.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<aio.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<monetary.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<mqueue.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<stdio.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<sys/msg.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<sys/uio.h>", kPublic },
|
|
{ "ssize_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "stat", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "stat", kPrivate, "<ftw.h>", kPublic },
|
|
{ "suseconds_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "suseconds_t", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "suseconds_t", kPrivate, "<sys/time.h>", kPublic },
|
|
{ "time_t", kPrivate, "<time.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sched.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sys/msg.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sys/sem.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sys/shm.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sys/time.h>", kPublic },
|
|
{ "time_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "time_t", kPrivate, "<utime.h>", kPublic },
|
|
{ "timer_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "timer_t", kPrivate, "<time.h>", kPublic },
|
|
{ "timespec", kPrivate, "<time.h>", kPublic },
|
|
{ "timespec", kPrivate, "<aio.h>", kPublic },
|
|
{ "timespec", kPrivate, "<mqueue.h>", kPublic },
|
|
{ "timespec", kPrivate, "<sched.h>", kPublic },
|
|
{ "timespec", kPrivate, "<signal.h>", kPublic },
|
|
{ "timespec", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "timespec", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "timeval", kPrivate, "<sys/time.h>", kPublic },
|
|
{ "timeval", kPrivate, "<sys/resource.h>", kPublic },
|
|
{ "timeval", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "timeval", kPrivate, "<utmpx.h>", kPublic },
|
|
{ "tm", kPrivate, "<time.h>", kPublic },
|
|
{ "u_char", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "u_char", kPrivate, "<rpc/types.h>", kPublic },
|
|
{ "uid_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "uid_t", kPrivate, "<pwd.h>", kPublic },
|
|
{ "uid_t", kPrivate, "<signal.h>", kPublic },
|
|
{ "uid_t", kPrivate, "<stropts.h>", kPublic },
|
|
{ "uid_t", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "uid_t", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "uid_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "useconds_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "useconds_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "wchar_t", kPrivate, "<stddef.h>", kPublic },
|
|
{ "wchar_t", kPrivate, "<stdlib.h>", kPublic },
|
|
// It is unspecified if the cname headers provide ::size_t.
|
|
// <locale.h> is the one header which defines NULL but not size_t.
|
|
{ "size_t", kPrivate, "<stddef.h>", kPublic }, // 'canonical' location for size_t
|
|
{ "size_t", kPrivate, "<aio.h>", kPublic },
|
|
{ "size_t", kPrivate, "<glob.h>", kPublic },
|
|
{ "size_t", kPrivate, "<grp.h>", kPublic },
|
|
{ "size_t", kPrivate, "<iconv.h>", kPublic },
|
|
{ "size_t", kPrivate, "<monetary.h>", kPublic },
|
|
{ "size_t", kPrivate, "<mqueue.h>", kPublic },
|
|
{ "size_t", kPrivate, "<ndbm.h>", kPublic },
|
|
{ "size_t", kPrivate, "<pwd.h>", kPublic },
|
|
{ "size_t", kPrivate, "<regex.h>", kPublic },
|
|
{ "size_t", kPrivate, "<search.h>", kPublic },
|
|
{ "size_t", kPrivate, "<signal.h>", kPublic },
|
|
{ "size_t", kPrivate, "<stdio.h>", kPublic },
|
|
{ "size_t", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "size_t", kPrivate, "<string.h>", kPublic },
|
|
{ "size_t", kPrivate, "<strings.h>", kPublic },
|
|
{ "size_t", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "size_t", kPrivate, "<sys/msg.h>", kPublic },
|
|
{ "size_t", kPrivate, "<sys/sem.h>", kPublic },
|
|
{ "size_t", kPrivate, "<sys/shm.h>", kPublic },
|
|
{ "size_t", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "size_t", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "size_t", kPrivate, "<sys/uio.h>", kPublic },
|
|
{ "size_t", kPrivate, "<time.h>", kPublic },
|
|
{ "size_t", kPrivate, "<uchar.h>", kPublic },
|
|
{ "size_t", kPrivate, "<unistd.h>", kPublic },
|
|
{ "size_t", kPrivate, "<wchar.h>", kPublic },
|
|
{ "size_t", kPrivate, "<wordexp.h>", kPublic },
|
|
// Macros that can be defined in more than one file, don't have the
|
|
// same __foo_defined guard that other types do, so the grep above
|
|
// doesn't discover them. Until I figure out a better way, I just
|
|
// add them in by hand as I discover them.
|
|
{ "EOF", kPrivate, "<stdio.h>", kPublic },
|
|
{ "EOF", kPrivate, "<libio.h>", kPublic },
|
|
{ "FILE", kPrivate, "<stdio.h>", kPublic },
|
|
{ "MAP_POPULATE", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "MAP_POPULATE", kPrivate, "<linux/mman.h>", kPublic },
|
|
{ "MAP_STACK", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "MAP_STACK", kPrivate, "<linux/mman.h>", kPublic },
|
|
{ "MAXHOSTNAMELEN", kPrivate, "<sys/param.h>", kPublic },
|
|
{ "MAXHOSTNAMELEN", kPrivate, "<protocols/timed.h>", kPublic },
|
|
{ "SIGABRT", kPrivate, "<signal.h>", kPublic },
|
|
{ "SIGCHLD", kPrivate, "<signal.h>", kPublic },
|
|
{ "SIGCHLD", kPrivate, "<linux/signal.h>", kPublic },
|
|
{ "va_list", kPrivate, "<stdarg.h>", kPublic },
|
|
{ "va_list", kPrivate, "<stdio.h>", kPublic },
|
|
{ "va_list", kPrivate, "<wchar.h>", kPublic },
|
|
// These are symbols that could be defined in either stdlib.h or
|
|
// malloc.h, but we always want the stdlib location.
|
|
{ "malloc", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "calloc", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "realloc", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "free", kPrivate, "<stdlib.h>", kPublic },
|
|
// Entries for NULL
|
|
{ "NULL", kPrivate, "<stddef.h>", kPublic }, // 'canonical' location for NULL
|
|
{ "NULL", kPrivate, "<clocale>", kPublic },
|
|
{ "NULL", kPrivate, "<cstddef>", kPublic },
|
|
{ "NULL", kPrivate, "<cstdio>", kPublic },
|
|
{ "NULL", kPrivate, "<cstdlib>", kPublic },
|
|
{ "NULL", kPrivate, "<cstring>", kPublic },
|
|
{ "NULL", kPrivate, "<ctime>", kPublic },
|
|
{ "NULL", kPrivate, "<cwchar>", kPublic },
|
|
{ "NULL", kPrivate, "<locale.h>", kPublic },
|
|
{ "NULL", kPrivate, "<stdio.h>", kPublic },
|
|
{ "NULL", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "NULL", kPrivate, "<string.h>", kPublic },
|
|
{ "NULL", kPrivate, "<time.h>", kPublic },
|
|
{ "NULL", kPrivate, "<unistd.h>", kPublic },
|
|
{ "NULL", kPrivate, "<wchar.h>", kPublic },
|
|
};
|
|
|
|
// Symbol -> include mappings for GNU libstdc++
|
|
const IncludeMapEntry libstdcpp_symbol_map[] = {
|
|
// Kludge time: almost all STL types take an allocator, but they
|
|
// almost always use the default value. Usually we detect that
|
|
// and don't try to do IWYU, but sometimes it passes through.
|
|
// For instance, when adding two strings, we end up calling
|
|
// template<_CharT,_Traits,_Alloc> ... operator+(
|
|
// basic_string<_CharT,_Traits,_Alloc>, ...)
|
|
// These look like normal template args to us, so we see they're
|
|
// used and declare an iwyu dependency, even though we don't need
|
|
// to #include the traits or alloc type ourselves. The surest way
|
|
// to deal with this is to just say that everyone provides
|
|
// std::allocator. We can add more here at need.
|
|
{ "std::allocator", kPrivate, "<memory>", kPublic },
|
|
{ "std::allocator", kPrivate, "<string>", kPublic },
|
|
{ "std::allocator", kPrivate, "<vector>", kPublic },
|
|
{ "std::allocator", kPrivate, "<map>", kPublic },
|
|
{ "std::allocator", kPrivate, "<set>", kPublic },
|
|
// A similar kludge for std::char_traits. basic_string,
|
|
// basic_ostream and basic_istream have this as a default template
|
|
// argument, and sometimes it bleeds through when clang desugars the
|
|
// string/ostream/istream type.
|
|
{ "std::char_traits", kPrivate, "<string>", kPublic },
|
|
{ "std::char_traits", kPrivate, "<ostream>", kPublic },
|
|
{ "std::char_traits", kPrivate, "<istream>", kPublic },
|
|
|
|
{ "std::size_t", kPrivate, "<cstddef>", kPublic }, // 'canonical' location for std::size_t
|
|
{ "std::size_t", kPrivate, "<cstdio>", kPublic },
|
|
{ "std::size_t", kPrivate, "<cstdlib>", kPublic },
|
|
{ "std::size_t", kPrivate, "<cstring>", kPublic },
|
|
{ "std::size_t", kPrivate, "<ctime>", kPublic },
|
|
{ "std::size_t", kPrivate, "<cuchar>", kPublic },
|
|
{ "std::size_t", kPrivate, "<cwchar>", kPublic },
|
|
};
|
|
|
|
const IncludeMapEntry libc_include_map[] = {
|
|
// Private -> public include mappings for GNU libc
|
|
// ( cd /usr/include && grep '^ *# *include' {sys/,net/,}* | perl -nle 'm/^([^:]+).*<([^>]+)>/ && print qq@ { "<$2>", kPrivate, "<$1>", kPublic },@' | grep bits/ | sort )
|
|
// When I saw more than one mapping for these, I typically picked
|
|
// what I thought was the "best" one.
|
|
{ "<bits/a.out.h>", kPrivate, "<a.out.h>", kPublic },
|
|
{ "<bits/auxv.h>", kPrivate, "<sys/auxv.h>", kPublic },
|
|
{ "<bits/byteswap.h>", kPrivate, "<byteswap.h>", kPublic },
|
|
{ "<bits/cmathcalls.h>", kPrivate, "<complex.h>", kPublic },
|
|
{ "<bits/confname.h>", kPrivate, "<unistd.h>", kPublic },
|
|
{ "<bits/dirent.h>", kPrivate, "<dirent.h>", kPublic },
|
|
{ "<bits/dlfcn.h>", kPrivate, "<dlfcn.h>", kPublic },
|
|
{ "<bits/elfclass.h>", kPrivate, "<link.h>", kPublic },
|
|
{ "<bits/endian.h>", kPrivate, "<endian.h>", kPublic },
|
|
{ "<bits/environments.h>", kPrivate, "<unistd.h>", kPublic },
|
|
{ "<bits/epoll.h>", kPrivate, "<sys/epoll.h>", kPublic },
|
|
{ "<bits/errno.h>", kPrivate, "<errno.h>", kPublic },
|
|
{ "<bits/error.h>", kPrivate, "<error.h>", kPublic },
|
|
{ "<bits/eventfd.h>", kPrivate, "<sys/eventfd.h>", kPublic },
|
|
{ "<bits/fcntl.h>", kPrivate, "<fcntl.h>", kPublic },
|
|
{ "<bits/fcntl2.h>", kPrivate, "<fcntl.h>", kPublic },
|
|
{ "<bits/fenv.h>", kPrivate, "<fenv.h>", kPublic },
|
|
{ "<bits/fenvinline.h>", kPrivate, "<fenv.h>", kPublic },
|
|
{ "<bits/huge_val.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/huge_valf.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/huge_vall.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/hwcap.h>", kPrivate, "<sys/auxv.h>", kPublic },
|
|
{ "<bits/inf.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/inotify.h>", kPrivate, "<sys/inotify.h>", kPublic },
|
|
{ "<bits/ioctl-types.h>", kPrivate, "<sys/ioctl.h>", kPublic },
|
|
{ "<bits/ioctls.h>", kPrivate, "<sys/ioctl.h>", kPublic },
|
|
{ "<bits/ipc.h>", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "<bits/ipctypes.h>", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "<bits/libio-ldbl.h>", kPrivate, "<libio.h>", kPublic },
|
|
{ "<bits/link.h>", kPrivate, "<link.h>", kPublic },
|
|
{ "<bits/locale.h>", kPrivate, "<locale.h>", kPublic },
|
|
{ "<bits/math-finite.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/mathcalls.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/mathdef.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/mathinline.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/mman.h>", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "<bits/mman-shared.h>", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "<bits/monetary-ldbl.h>", kPrivate, "<monetary.h>", kPublic },
|
|
{ "<bits/mqueue.h>", kPrivate, "<mqueue.h>", kPublic },
|
|
{ "<bits/mqueue2.h>", kPrivate, "<mqueue.h>", kPublic },
|
|
{ "<bits/msq.h>", kPrivate, "<sys/msg.h>", kPublic },
|
|
{ "<bits/nan.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/netdb.h>", kPrivate, "<netdb.h>", kPublic },
|
|
{ "<bits/param.h>", kPrivate, "<sys/param.h>", kPublic },
|
|
{ "<bits/poll.h>", kPrivate, "<sys/poll.h>", kPrivate },
|
|
{ "<bits/poll2.h>", kPrivate, "<sys/poll.h>", kPrivate },
|
|
{ "<bits/posix1_lim.h>", kPrivate, "<limits.h>", kPublic },
|
|
{ "<bits/posix2_lim.h>", kPrivate, "<limits.h>", kPublic },
|
|
{ "<bits/posix_opt.h>", kPrivate, "<unistd.h>", kPublic },
|
|
{ "<bits/printf-ldbl.h>", kPrivate, "<printf.h>", kPublic },
|
|
{ "<bits/pthreadtypes.h>", kPrivate, "<pthread.h>", kPublic },
|
|
{ "<bits/resource.h>", kPrivate, "<sys/resource.h>", kPublic },
|
|
{ "<bits/sched.h>", kPrivate, "<sched.h>", kPublic },
|
|
{ "<bits/select.h>", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "<bits/select2.h>", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "<bits/sem.h>", kPrivate, "<sys/sem.h>", kPublic },
|
|
{ "<bits/semaphore.h>", kPrivate, "<semaphore.h>", kPublic },
|
|
{ "<bits/setjmp.h>", kPrivate, "<setjmp.h>", kPublic },
|
|
{ "<bits/setjmp2.h>", kPrivate, "<setjmp.h>", kPublic },
|
|
{ "<bits/shm.h>", kPrivate, "<sys/shm.h>", kPublic },
|
|
{ "<bits/sigaction.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/sigcontext.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/siginfo.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/signum.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/sigset.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/sigstack.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/sigthread.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/sockaddr.h>", kPrivate, "<sys/un.h>", kPublic },
|
|
{ "<bits/socket.h>", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "<bits/socket2.h>", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "<bits/socket_type.h>", kPrivate, "<sys/socket.h>", kPublic },
|
|
{ "<bits/stab.def>", kPrivate, "<stab.h>", kPublic },
|
|
{ "<bits/stat.h>", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "<bits/statfs.h>", kPrivate, "<sys/statfs.h>", kPublic },
|
|
{ "<bits/statvfs.h>", kPrivate, "<sys/statvfs.h>", kPublic },
|
|
{ "<bits/stdio-ldbl.h>", kPrivate, "<stdio.h>", kPublic },
|
|
{ "<bits/stdio-lock.h>", kPrivate, "<libio.h>", kPublic },
|
|
{ "<bits/stdio.h>", kPrivate, "<stdio.h>", kPublic },
|
|
{ "<bits/stdio2.h>", kPrivate, "<stdio.h>", kPublic },
|
|
{ "<bits/stdio_lim.h>", kPrivate, "<stdio.h>", kPublic },
|
|
{ "<bits/stdlib-bsearch.h>", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "<bits/stdlib-float.h>", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "<bits/stdlib-ldbl.h>", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "<bits/stdlib.h>", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "<bits/string.h>", kPrivate, "<string.h>", kPublic },
|
|
{ "<bits/string2.h>", kPrivate, "<string.h>", kPublic },
|
|
{ "<bits/string3.h>", kPrivate, "<string.h>", kPublic },
|
|
{ "<bits/stropts.h>", kPrivate, "<stropts.h>", kPublic },
|
|
{ "<bits/struct_stat.h>", kPrivate, "<sys/stat.h>", kPublic },
|
|
{ "<bits/struct_stat.h>", kPrivate, "<ftw.h>", kPublic },
|
|
{ "<bits/sys_errlist.h>", kPrivate, "<stdio.h>", kPublic },
|
|
{ "<bits/syscall.h>", kPrivate, "<sys/syscall.h>", kPublic },
|
|
{ "<bits/sysctl.h>", kPrivate, "<sys/sysctl.h>", kPublic },
|
|
{ "<bits/syslog-ldbl.h>", kPrivate, "<sys/syslog.h>", kPrivate },
|
|
{ "<bits/syslog-path.h>", kPrivate, "<sys/syslog.h>", kPrivate },
|
|
{ "<bits/syslog.h>", kPrivate, "<sys/syslog.h>", kPrivate },
|
|
{ "<bits/termios-c_lflag.h>", kPrivate, "<termios.h>", kPublic },
|
|
{ "<bits/termios-struct.h>", kPrivate, "<termios.h>", kPublic },
|
|
{ "<bits/termios-tcflow.h>", kPrivate, "<termios.h>", kPublic },
|
|
{ "<bits/termios.h>", kPrivate, "<termios.h>", kPublic },
|
|
{ "<bits/time.h>", kPrivate, "<time.h>", kPublic },
|
|
{ "<bits/time.h>", kPrivate, "<sys/time.h>", kPublic },
|
|
{ "<bits/timerfd.h>", kPrivate, "<sys/timerfd.h>", kPublic },
|
|
{ "<bits/timex.h>", kPrivate, "<sys/timex.h>", kPublic },
|
|
{ "<bits/types.h>", kPrivate, "<sys/types.h>", kPublic },
|
|
{ "<bits/types/siginfo_t.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/types/siginfo_t.h>", kPrivate, "<sys/wait.h>", kPublic },
|
|
{ "<bits/uio.h>", kPrivate, "<sys/uio.h>", kPublic },
|
|
{ "<bits/unistd.h>", kPrivate, "<unistd.h>", kPublic },
|
|
{ "<bits/ustat.h>", kPrivate, "<sys/ustat.h>", kPrivate },
|
|
{ "<bits/utmp.h>", kPrivate, "<utmp.h>", kPublic },
|
|
{ "<bits/utmpx.h>", kPrivate, "<utmpx.h>", kPublic },
|
|
{ "<bits/utsname.h>", kPrivate, "<sys/utsname.h>", kPublic },
|
|
{ "<bits/waitflags.h>", kPrivate, "<sys/wait.h>", kPublic },
|
|
{ "<bits/waitstatus.h>", kPrivate, "<sys/wait.h>", kPublic },
|
|
{ "<bits/wchar-ldbl.h>", kPrivate, "<wchar.h>", kPublic },
|
|
{ "<bits/wchar.h>", kPrivate, "<wchar.h>", kPublic },
|
|
{ "<bits/wchar2.h>", kPrivate, "<wchar.h>", kPublic },
|
|
{ "<bits/wordsize.h>", kPrivate, "<limits.h>", kPublic },
|
|
{ "<bits/xopen_lim.h>", kPrivate, "<limits.h>", kPublic },
|
|
{ "<bits/xtitypes.h>", kPrivate, "<stropts.h>", kPublic },
|
|
// Sometimes libc tells you what mapping to do via an '#error':
|
|
// # error "Never use <bits/dlfcn.h> directly; include <dlfcn.h> instead."
|
|
// or
|
|
// # error "Never include <bits/socket_type.h> directly; use <sys/socket.h> instead."
|
|
// ( cd /usr/include && grep -R '^ *# *error "Never use\|include' * | perl -nle 'm/<([^>]+).*directly.*<([^>]+)/ && print qq@ { "<$1>", kPrivate, "<$2>", kPublic },@' | sort )
|
|
{ "<bits/a.out.h>", kPrivate, "<a.out.h>", kPublic },
|
|
{ "<bits/byteswap-16.h>", kPrivate, "<byteswap.h>", kPublic },
|
|
{ "<bits/byteswap.h>", kPrivate, "<byteswap.h>", kPublic },
|
|
{ "<bits/cmathcalls.h>", kPrivate, "<complex.h>", kPublic },
|
|
{ "<bits/confname.h>", kPrivate, "<unistd.h>", kPublic },
|
|
{ "<bits/dirent.h>", kPrivate, "<dirent.h>", kPublic },
|
|
{ "<bits/dlfcn.h>", kPrivate, "<dlfcn.h>", kPublic },
|
|
{ "<bits/elfclass.h>", kPrivate, "<link.h>", kPublic },
|
|
{ "<bits/endian.h>", kPrivate, "<endian.h>", kPublic },
|
|
{ "<bits/epoll.h>", kPrivate, "<sys/epoll.h>", kPublic },
|
|
{ "<bits/eventfd.h>", kPrivate, "<sys/eventfd.h>", kPublic },
|
|
{ "<bits/fcntl-linux.h>", kPrivate, "<fcntl.h>", kPublic },
|
|
{ "<bits/fcntl.h>", kPrivate, "<fcntl.h>", kPublic },
|
|
{ "<bits/fenv.h>", kPrivate, "<fenv.h>", kPublic },
|
|
{ "<bits/huge_val.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/huge_valf.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/huge_vall.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/in.h>", kPrivate, "<netinet/in.h>", kPublic },
|
|
{ "<bits/inf.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/inotify.h>", kPrivate, "<sys/inotify.h>", kPublic },
|
|
{ "<bits/ioctl-types.h>", kPrivate, "<sys/ioctl.h>", kPublic },
|
|
{ "<bits/ioctls.h>", kPrivate, "<sys/ioctl.h>", kPublic },
|
|
{ "<bits/ipc.h>", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "<bits/ipctypes.h>", kPrivate, "<sys/ipc.h>", kPublic },
|
|
{ "<bits/locale.h>", kPrivate, "<locale.h>", kPublic },
|
|
{ "<bits/math-finite.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/mathdef.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/mathinline.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/mman-linux.h>", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "<bits/mman.h>", kPrivate, "<sys/mman.h>", kPublic },
|
|
{ "<bits/mqueue.h>", kPrivate, "<mqueue.h>", kPublic },
|
|
{ "<bits/msq.h>", kPrivate, "<sys/msg.h>", kPublic },
|
|
{ "<bits/nan.h>", kPrivate, "<math.h>", kPublic },
|
|
{ "<bits/param.h>", kPrivate, "<sys/param.h>", kPublic },
|
|
{ "<bits/poll.h>", kPrivate, "<sys/poll.h>", kPrivate },
|
|
{ "<bits/predefs.h>", kPrivate, "<features.h>", kPublic },
|
|
{ "<bits/resource.h>", kPrivate, "<sys/resource.h>", kPublic },
|
|
{ "<bits/select.h>", kPrivate, "<sys/select.h>", kPublic },
|
|
{ "<bits/semaphore.h>", kPrivate, "<semaphore.h>", kPublic },
|
|
{ "<bits/sigcontext.h>", kPrivate, "<signal.h>", kPublic },
|
|
{ "<bits/signalfd.h>", kPrivate, "<sys/signalfd.h>", kPublic },
|
|
{ "<bits/stdlib-float.h>", kPrivate, "<stdlib.h>", kPublic },
|
|
{ "<bits/string.h>", kPrivate, "<string.h>", kPublic },
|
|
{ "<bits/string2.h>", kPrivate, "<string.h>", kPublic },
|
|
{ "<bits/string3.h>", kPrivate, "<string.h>", kPublic },
|
|
{ "<bits/timerfd.h>", kPrivate, "<sys/timerfd.h>", kPublic },
|
|
{ "<bits/typesizes.h>", kPrivate, "<sys/types.h>", kPublic },
|
|
// Top-level #includes that just forward to another file:
|
|
// $ for i in /usr/include/*; do [ -f $i ] && [ `wc -l < $i` = 1 ] && echo $i; done
|
|
// (poll.h, syscall.h, syslog.h, ustat.h, wait.h).
|
|
// For each file, I looked at the list of canonical header files --
|
|
// http://www.opengroup.org/onlinepubs/9699919799/idx/head.html --
|
|
// to decide which of the two files is canonical. If neither is
|
|
// on the POSIX.1 1998 list, I just choose the top-level one.
|
|
{ "<sys/poll.h>", kPrivate, "<poll.h>", kPublic },
|
|
{ "<sys/syslog.h>", kPrivate, "<syslog.h>", kPublic },
|
|
{ "<sys/ustat.h>", kPrivate, "<ustat.h>", kPublic },
|
|
{ "<wait.h>", kPrivate, "<sys/wait.h>", kPublic },
|
|
// These are all files in bits/ that delegate to asm/ and linux/ to
|
|
// do all (or lots) of the work. Note these are private->private.
|
|
// $ for i in /usr/include/bits/*; do for dir in asm linux; do grep -H -e $dir/`basename $i` $i; done; done
|
|
{ "<linux/errno.h>", kPrivate, "<bits/errno.h>", kPrivate },
|
|
{ "<asm/ioctls.h>", kPrivate, "<bits/ioctls.h>", kPrivate },
|
|
{ "<asm/socket.h>", kPrivate, "<bits/socket.h>", kPrivate },
|
|
{ "<linux/socket.h>", kPrivate, "<bits/socket.h>", kPrivate },
|
|
// Some asm files have 32- and 64-bit variants:
|
|
// $ ls /usr/include/asm/*_{32,64}.h
|
|
{ "<asm/posix_types_32.h>", kPrivate, "<asm/posix_types.h>", kPublic },
|
|
{ "<asm/posix_types_64.h>", kPrivate, "<asm/posix_types.h>", kPublic },
|
|
{ "<asm/unistd_32.h>", kPrivate, "<asm/unistd.h>", kPrivate },
|
|
{ "<asm/unistd_64.h>", kPrivate, "<asm/unistd.h>", kPrivate },
|
|
// I don't know what grep would have found these. I found them
|
|
// via user report.
|
|
{ "<asm/errno.h>", kPrivate, "<errno.h>", kPublic },
|
|
{ "<asm/errno-base.h>", kPrivate, "<errno.h>", kPublic },
|
|
{ "<asm/ptrace-abi.h>", kPrivate, "<asm/ptrace.h>", kPublic },
|
|
{ "<asm/unistd.h>", kPrivate, "<sys/syscall.h>", kPublic },
|
|
{ "<linux/limits.h>", kPrivate, "<limits.h>", kPublic }, // PATH_MAX
|
|
{ "<linux/prctl.h>", kPrivate, "<sys/prctl.h>", kPublic },
|
|
{ "<sys/ucontext.h>", kPrivate, "<ucontext.h>", kPublic },
|
|
// Exports guaranteed by the C standard
|
|
{ "<stdint.h>", kPublic, "<inttypes.h>", kPublic },
|
|
};
|
|
|
|
const IncludeMapEntry stdlib_c_include_map[] = {
|
|
// Allow the C++ wrappers around C files. Without these mappings,
|
|
// if you #include <cstdio>, iwyu will tell you to replace it with
|
|
// <stdio.h>, which is where the symbols are actually defined. We
|
|
// inhibit that behavior to keep the <cstdio> alone. Note this is a
|
|
// public-to-public mapping: we don't want to *replace* <assert.h>
|
|
// with <cassert>, we just want to avoid suggesting changing
|
|
// <cassert> back to <assert.h>. (If you *did* want to replace
|
|
// assert.h with cassert, you'd change it to a public->private
|
|
// mapping.) Here is how I identified the files to map:
|
|
// $ for i in /usr/include/c++/4.4/c* ; do ls /usr/include/`basename $i | cut -b2-`.h /usr/lib/gcc/*/4.4/include/`basename $i | cut -b2-`.h 2>/dev/null ; done
|
|
//
|
|
// These headers are defined in [headers.cpp.c].
|
|
// https://github.com/cplusplus/draft/blob/c+%2B20/source/lib-intro.tex
|
|
//
|
|
// $ curl -s -N https://raw.githubusercontent.com/cplusplus/draft/c%2B%2B20/source/lib-intro.tex | sed -n '/begin{multicolfloattable}.*{headers.cpp.c}/,/end{multicolfloattable}/p' lib-intro.tex | grep tcode | perl -nle 'm/tcode{<c(.*)>}/ && print qq@ { "<$1.h>", kPublic, "<c$1>", kPublic },@' | sort
|
|
{ "<assert.h>", kPublic, "<cassert>", kPublic },
|
|
{ "<complex.h>", kPublic, "<ccomplex>", kPublic },
|
|
{ "<ctype.h>", kPublic, "<cctype>", kPublic },
|
|
{ "<errno.h>", kPublic, "<cerrno>", kPublic },
|
|
{ "<fenv.h>", kPublic, "<cfenv>", kPublic },
|
|
{ "<float.h>", kPublic, "<cfloat>", kPublic },
|
|
{ "<inttypes.h>", kPublic, "<cinttypes>", kPublic },
|
|
{ "<iso646.h>", kPublic, "<ciso646>", kPublic },
|
|
{ "<limits.h>", kPublic, "<climits>", kPublic },
|
|
{ "<locale.h>", kPublic, "<clocale>", kPublic },
|
|
{ "<math.h>", kPublic, "<cmath>", kPublic },
|
|
{ "<setjmp.h>", kPublic, "<csetjmp>", kPublic },
|
|
{ "<signal.h>", kPublic, "<csignal>", kPublic },
|
|
{ "<stdalign.h>", kPublic, "<cstdalign>", kPublic },
|
|
{ "<stdarg.h>", kPublic, "<cstdarg>", kPublic },
|
|
{ "<stdbool.h>", kPublic, "<cstdbool>", kPublic },
|
|
{ "<stddef.h>", kPublic, "<cstddef>", kPublic },
|
|
{ "<stdint.h>", kPublic, "<cstdint>", kPublic },
|
|
{ "<stdio.h>", kPublic, "<cstdio>", kPublic },
|
|
{ "<stdlib.h>", kPublic, "<cstdlib>", kPublic },
|
|
{ "<string.h>", kPublic, "<cstring>", kPublic },
|
|
{ "<tgmath.h>", kPublic, "<ctgmath>", kPublic },
|
|
{ "<time.h>", kPublic, "<ctime>", kPublic },
|
|
{ "<uchar.h>", kPublic, "<cuchar>", kPublic },
|
|
{ "<wchar.h>", kPublic, "<cwchar>", kPublic },
|
|
{ "<wctype.h>", kPublic, "<cwctype>", kPublic },
|
|
};
|
|
|
|
const char* stdlib_cpp_public_headers[] = {
|
|
// These headers are defined in [headers.cpp].
|
|
// https://github.com/cplusplus/draft/blob/c+%2B20/source/lib-intro.tex
|
|
//
|
|
// $ curl -s -N https://raw.githubusercontent.com/cplusplus/draft/c%2B%2B20/source/lib-intro.tex | sed -n '/begin{multicolfloattable}.*{headers.cpp}/,/end{multicolfloattable}/p' lib-intro.tex | grep tcode | perl -nle 'm/tcode{(.*)}/ && print qq@ "$1",@' | sort
|
|
"<algorithm>",
|
|
"<any>",
|
|
"<array>",
|
|
"<atomic>",
|
|
"<barrier>",
|
|
"<bit>",
|
|
"<bitset>",
|
|
"<charconv>",
|
|
"<chrono>",
|
|
"<codecvt>",
|
|
"<compare>",
|
|
"<complex>",
|
|
"<concepts>",
|
|
"<condition_variable>",
|
|
"<coroutine>",
|
|
"<deque>",
|
|
"<exception>",
|
|
"<execution>",
|
|
"<filesystem>",
|
|
"<format>",
|
|
"<forward_list>",
|
|
"<fstream>",
|
|
"<functional>",
|
|
"<future>",
|
|
"<initializer_list>",
|
|
"<iomanip>",
|
|
"<ios>",
|
|
"<iosfwd>",
|
|
"<iostream>",
|
|
"<istream>",
|
|
"<iterator>",
|
|
"<latch>",
|
|
"<limits>",
|
|
"<list>",
|
|
"<locale>",
|
|
"<map>",
|
|
"<memory>",
|
|
"<memory_resource>",
|
|
"<mutex>",
|
|
"<new>",
|
|
"<numbers>",
|
|
"<numeric>",
|
|
"<optional>",
|
|
"<ostream>",
|
|
"<queue>",
|
|
"<random>",
|
|
"<ranges>",
|
|
"<ratio>",
|
|
"<regex>",
|
|
"<scoped_allocator>",
|
|
"<semaphore>",
|
|
"<set>",
|
|
"<shared_mutex>",
|
|
"<source_location>",
|
|
"<span>",
|
|
"<sstream>",
|
|
"<stack>",
|
|
"<stdexcept>",
|
|
"<stop_token>",
|
|
"<streambuf>",
|
|
"<string>",
|
|
"<string_view>",
|
|
"<strstream>",
|
|
"<syncstream>",
|
|
"<system_error>",
|
|
"<thread>",
|
|
"<tuple>",
|
|
"<typeindex>",
|
|
"<typeinfo>",
|
|
"<type_traits>",
|
|
"<unordered_map>",
|
|
"<unordered_set>",
|
|
"<utility>",
|
|
"<valarray>",
|
|
"<variant>",
|
|
"<vector>",
|
|
"<version>",
|
|
};
|
|
|
|
// Private -> public include mappings for GNU libstdc++
|
|
//
|
|
// Note: make sure to sync this setting with gcc.stl.headers.imp
|
|
//
|
|
const IncludeMapEntry libstdcpp_include_map[] = {
|
|
// cd /usr/include/c++/10 && grep -r headername | perl -nle 'm/^([^:]+).*@headername\{([^,]*)\}/ && print qq@ { "<$1>", kPrivate, "<$2>", kPublic },@' | sort -u
|
|
{ "<backward/auto_ptr.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<backward/backward_warning.h>", kPrivate, "<iosfwd>", kPublic },
|
|
{ "<backward/binders.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/algorithmfwd.h>", kPrivate, "<algorithm>", kPublic },
|
|
{ "<bits/allocated_ptr.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/allocator.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/alloc_traits.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/atomic_base.h>", kPrivate, "<atomic>", kPublic },
|
|
{ "<bits/atomic_lockfree_defines.h>", kPrivate, "<atomic>", kPublic },
|
|
{ "<bits/basic_ios.h>", kPrivate, "<ios>", kPublic },
|
|
{ "<bits/basic_ios.tcc>", kPrivate, "<ios>", kPublic },
|
|
{ "<bits/basic_string.h>", kPrivate, "<string>", kPublic },
|
|
{ "<bits/basic_string.tcc>", kPrivate, "<string>", kPublic },
|
|
{ "<bits/boost_concept_check.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/c++0x_warning.h>", kPrivate, "<iosfwd>", kPublic },
|
|
{ "<bits/charconv.h>", kPrivate, "<charconv>", kPublic },
|
|
{ "<bits/char_traits.h>", kPrivate, "<string>", kPublic },
|
|
{ "<bits/codecvt.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/concept_check.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/cpp_type_traits.h>", kPrivate, "<ext/type_traits>", kPublic },
|
|
{ "<bits/cxxabi_forced.h>", kPrivate, "<cxxabi.h>", kPublic },
|
|
{ "<bits/deque.tcc>", kPrivate, "<deque>", kPublic },
|
|
{ "<bits/exception_defines.h>", kPrivate, "<exception>", kPublic },
|
|
{ "<bits/exception_ptr.h>", kPrivate, "<exception>", kPublic },
|
|
{ "<bits/forward_list.h>", kPrivate, "<forward_list>", kPublic },
|
|
{ "<bits/forward_list.tcc>", kPrivate, "<forward_list>", kPublic },
|
|
{ "<bits/fs_dir.h>", kPrivate, "<filesystem>", kPublic },
|
|
{ "<bits/fs_fwd.h>", kPrivate, "<filesystem>", kPublic },
|
|
{ "<bits/fs_ops.h>", kPrivate, "<filesystem>", kPublic },
|
|
{ "<bits/fs_path.h>", kPrivate, "<filesystem>", kPublic },
|
|
{ "<bits/fstream.tcc>", kPrivate, "<fstream>", kPublic },
|
|
{ "<bits/functexcept.h>", kPrivate, "<exception>", kPublic },
|
|
{ "<bits/functional_hash.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/gslice_array.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/gslice.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/hash_bytes.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/indirect_array.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/int_limits.h>", kPrivate, "<limits>", kPublic },
|
|
{ "<bits/invoke.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/ios_base.h>", kPrivate, "<ios>", kPublic },
|
|
{ "<bits/istream.tcc>", kPrivate, "<istream>", kPublic },
|
|
{ "<bits/iterator_concepts.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/list.tcc>", kPrivate, "<list>", kPublic },
|
|
{ "<bits/locale_classes.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/locale_classes.tcc>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/locale_conv.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/locale_facets.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/locale_facets_nonio.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/locale_facets_nonio.tcc>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/locale_facets.tcc>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/localefwd.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/mask_array.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/memoryfwd.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/move.h>", kPrivate, "<utility>", kPublic },
|
|
{ "<bits/nested_exception.h>", kPrivate, "<exception>", kPublic },
|
|
{ "<bits/ostream_insert.h>", kPrivate, "<ostream>", kPublic },
|
|
{ "<bits/ostream.tcc>", kPrivate, "<ostream>", kPublic },
|
|
{ "<bits/parse_numbers.h>", kPrivate, "<chrono>", kPublic },
|
|
{ "<bits/postypes.h>", kPrivate, "<iosfwd>", kPublic },
|
|
{ "<bits/predefined_ops.h>", kPrivate, "<algorithm>", kPublic },
|
|
{ "<bits/ptr_traits.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/quoted_string.h>", kPrivate, "<iomanip>", kPublic },
|
|
{ "<bits/random.h>", kPrivate, "<random>", kPublic },
|
|
{ "<bits/random.tcc>", kPrivate, "<random>", kPublic },
|
|
{ "<bits/range_access.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/range_cmp.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/ranges_algobase.h>", kPrivate, "<algorithm>", kPublic },
|
|
{ "<bits/ranges_algo.h>", kPrivate, "<algorithm>", kPublic },
|
|
{ "<bits/ranges_uninitialized.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/refwrap.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/regex_automaton.h>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_automaton.tcc>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_compiler.h>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_compiler.tcc>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_constants.h>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_error.h>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_executor.h>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_executor.tcc>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex.h>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_scanner.h>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex_scanner.tcc>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/regex.tcc>", kPrivate, "<regex>", kPublic },
|
|
{ "<bits/shared_ptr_atomic.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/shared_ptr_base.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/shared_ptr.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/slice_array.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/specfun.h>", kPrivate, "<cmath>", kPublic },
|
|
{ "<bits/sstream.tcc>", kPrivate, "<sstream>", kPublic },
|
|
{ "<bits/std_function.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/std_mutex.h>", kPrivate, "<mutex>", kPublic },
|
|
{ "<bits/stl_algobase.h>", kPrivate, "<algorithm>", kPublic },
|
|
{ "<bits/stl_algo.h>", kPrivate, "<algorithm>", kPublic },
|
|
{ "<bits/stl_bvector.h>", kPrivate, "<vector>", kPublic },
|
|
{ "<bits/stl_construct.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/stl_deque.h>", kPrivate, "<deque>", kPublic },
|
|
{ "<bits/stl_function.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<bits/stl_heap.h>", kPrivate, "<queue>", kPublic },
|
|
{ "<bits/stl_iterator_base_funcs.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/stl_iterator_base_types.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/stl_iterator.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/stl_list.h>", kPrivate, "<list>", kPublic },
|
|
{ "<bits/stl_map.h>", kPrivate, "<map>", kPublic },
|
|
{ "<bits/stl_multimap.h>", kPrivate, "<map>", kPublic },
|
|
{ "<bits/stl_multiset.h>", kPrivate, "<set>", kPublic },
|
|
{ "<bits/stl_numeric.h>", kPrivate, "<numeric>", kPublic },
|
|
{ "<bits/stl_pair.h>", kPrivate, "<utility>", kPublic },
|
|
{ "<bits/stl_queue.h>", kPrivate, "<queue>", kPublic },
|
|
{ "<bits/stl_raw_storage_iter.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/stl_relops.h>", kPrivate, "<utility>", kPublic },
|
|
{ "<bits/stl_set.h>", kPrivate, "<set>", kPublic },
|
|
{ "<bits/stl_stack.h>", kPrivate, "<stack>", kPublic },
|
|
{ "<bits/stl_tempbuf.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/stl_uninitialized.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/stl_vector.h>", kPrivate, "<vector>", kPublic },
|
|
{ "<bits/streambuf_iterator.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/streambuf.tcc>", kPrivate, "<streambuf>", kPublic },
|
|
{ "<bits/stream_iterator.h>", kPrivate, "<iterator>", kPublic },
|
|
{ "<bits/stringfwd.h>", kPrivate, "<string>", kPublic },
|
|
{ "<bits/string_view.tcc>", kPrivate, "<string_view>", kPublic },
|
|
{ "<bits/uniform_int_dist.h>", kPrivate, "<random>", kPublic },
|
|
{ "<bits/unique_lock.h>", kPrivate, "<mutex>", kPublic },
|
|
{ "<bits/unique_ptr.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/unordered_map.h>", kPrivate, "<unordered_map>", kPublic },
|
|
{ "<bits/unordered_set.h>", kPrivate, "<unordered_set>", kPublic },
|
|
{ "<bits/utility.h>", kPrivate, "<utility>", kPublic },
|
|
{ "<bits/valarray_after.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/valarray_array.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/valarray_array.tcc>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/valarray_before.h>", kPrivate, "<valarray>", kPublic },
|
|
{ "<bits/vector.tcc>", kPrivate, "<vector>", kPublic },
|
|
{ "<decimal/decimal.h>", kPrivate, "<decimal>", kPublic },
|
|
{ "<experimental/bits/fs_dir.h>", kPrivate, "<experimental/filesystem>", kPublic },
|
|
{ "<experimental/bits/fs_fwd.h>", kPrivate, "<experimental/filesystem>", kPublic },
|
|
{ "<experimental/bits/fs_ops.h>", kPrivate, "<experimental/filesystem>", kPublic },
|
|
{ "<experimental/bits/fs_path.h>", kPrivate, "<experimental/filesystem>", kPublic },
|
|
{ "<experimental/bits/net.h>", kPrivate, "<experimental/net>", kPublic },
|
|
{ "<experimental/bits/shared_ptr.h>", kPrivate, "<experimental/memory>", kPublic },
|
|
{ "<experimental/bits/string_view.tcc>", kPrivate, "<experimental/string_view>", kPublic },
|
|
{ "<ext/cast.h>", kPrivate, "<ext/pointer.h>", kPublic },
|
|
{ "<ext/random.tcc>", kPrivate, "<ext/random>", kPublic },
|
|
{ "<ext/rc_string_base.h>", kPrivate, "<ext/vstring.h>", kPublic },
|
|
{ "<ext/ropeimpl.h>", kPrivate, "<ext/rope>", kPublic },
|
|
{ "<ext/sso_string_base.h>", kPrivate, "<ext/vstring.h>", kPublic },
|
|
{ "<ext/vstring_fwd.h>", kPrivate, "<ext/vstring.h>", kPublic },
|
|
{ "<ext/vstring.tcc>", kPrivate, "<ext/vstring.h>", kPublic },
|
|
{ "<ext/vstring_util.h>", kPrivate, "<ext/vstring.h>", kPublic },
|
|
{ "<tr1/bessel_function.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/beta_function.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/ell_integral.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/exp_integral.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/functional_hash.h>", kPrivate, "<tr1/functional>", kPublic },
|
|
{ "<tr1/gamma.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/hypergeometric.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/legendre_function.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/modified_bessel_func.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/poly_hermite.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/poly_laguerre.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/random.h>", kPrivate, "<tr1/random>", kPublic },
|
|
{ "<tr1/random.tcc>", kPrivate, "<tr1/random>", kPublic },
|
|
{ "<tr1/riemann_zeta.tcc>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/shared_ptr.h>", kPrivate, "<tr1/memory>", kPublic },
|
|
{ "<tr1/special_function_util.h>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1/unordered_map.h>", kPrivate, "<tr1/unordered_map>", kPublic },
|
|
{ "<tr1/unordered_set.h>", kPrivate, "<tr1/unordered_set>", kPublic },
|
|
{ "<tr2/dynamic_bitset.tcc>", kPrivate, "<tr2/dynamic_bitset>", kPublic },
|
|
// cd /usr/include/x86_64-linux-gnu/c++/10 && grep -r headername | perl -nle 'm/^([^:]+).*@headername\{([^,]*)\}/ && print qq@ { "<$1>", kPrivate, "<$2>", kPublic },@' | sort -u
|
|
{ "<bits/basic_file.h>", kPrivate, "<ios>", kPublic },
|
|
{ "<bits/c++allocator.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/c++config.h>", kPrivate, "<iosfwd>", kPublic },
|
|
{ "<bits/c++config.h>", kPrivate, "<version>", kPublic },
|
|
{ "<bits/c++io.h>", kPrivate, "<ios>", kPublic },
|
|
{ "<bits/c++locale.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/cpu_defines.h>", kPrivate, "<iosfwd>", kPublic },
|
|
{ "<bits/ctype_base.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/ctype_inline.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/cxxabi_tweaks.h>", kPrivate, "<cxxabi.h>", kPublic },
|
|
{ "<bits/error_constants.h>", kPrivate, "<system_error>", kPublic },
|
|
{ "<bits/messages_members.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<bits/opt_random.h>", kPrivate, "<random>", kPublic },
|
|
{ "<bits/os_defines.h>", kPrivate, "<iosfwd>", kPublic },
|
|
{ "<bits/time_members.h>", kPrivate, "<locale>", kPublic },
|
|
{ "<ext/opt_random.h>", kPrivate, "<ext/random>", kPublic },
|
|
// ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && grep '^ *# *include' {ext/,tr1/,}* | perl -nle 'm/^([^:]+).*<([^>]+)>/ && print qq@ { "<$2>", kPrivate, "<$1>", kPublic },@' | grep -e bits/ -e tr1_impl/ | sort -u)
|
|
// I removed a lot of 'meaningless' dependencies -- for instance,
|
|
// <functional> #includes <bits/stringfwd.h>, but if someone is
|
|
// using strings, <functional> isn't enough to satisfy iwyu.
|
|
// We may need to add other dirs in future versions of gcc.
|
|
{ "<bits/atomic_word.h>", kPrivate, "<ext/atomicity.h>", kPublic },
|
|
{ "<bits/basic_file.h>", kPrivate, "<fstream>", kPublic },
|
|
{ "<bits/boost_sp_shared_count.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<bits/c++io.h>", kPrivate, "<ext/stdio_sync_filebuf.h>", kPublic },
|
|
{ "<bits/c++config.h>", kPrivate, "<cstddef>", kPublic },
|
|
{ "<bits/cmath.tcc>", kPrivate, "<cmath>", kPublic },
|
|
{ "<bits/codecvt.h>", kPrivate, "<fstream>", kPublic },
|
|
{ "<bits/cxxabi_tweaks.h>", kPrivate, "<cxxabi.h>", kPublic },
|
|
{ "<bits/functional_hash.h>", kPrivate, "<unordered_map>", kPublic },
|
|
{ "<bits/hashtable.h>", kPrivate, "<unordered_map>", kPublic },
|
|
{ "<bits/hashtable.h>", kPrivate, "<unordered_set>", kPublic },
|
|
{ "<bits/ios_base.h>", kPrivate, "<iostream>", kPublic },
|
|
{ "<bits/ios_base.h>", kPrivate, "<iomanip>", kPublic },
|
|
{ "<bits/postypes.h>", kPrivate, "<iostream>", kPublic },
|
|
{ "<bits/stl_pair.h>", kPrivate, "<tr1/utility>", kPublic },
|
|
{ "<bits/stl_tree.h>", kPrivate, "<map>", kPublic },
|
|
{ "<bits/stl_tree.h>", kPrivate, "<set>", kPublic },
|
|
{ "<tr1_impl/array>", kPrivate, "<array>", kPublic },
|
|
{ "<tr1_impl/array>", kPrivate, "<tr1/array>", kPublic },
|
|
{ "<tr1_impl/boost_shared_ptr.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<tr1_impl/boost_shared_ptr.h>", kPrivate, "<tr1/memory>", kPublic },
|
|
{ "<tr1_impl/boost_sp_counted_base.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<tr1_impl/boost_sp_counted_base.h>", kPrivate, "<tr1/memory>", kPublic },
|
|
{ "<tr1_impl/cctype>", kPrivate, "<cctype>", kPublic },
|
|
{ "<tr1_impl/cctype>", kPrivate, "<tr1/cctype>", kPublic },
|
|
{ "<tr1_impl/cfenv>", kPrivate, "<cfenv>", kPublic },
|
|
{ "<tr1_impl/cfenv>", kPrivate, "<tr1/cfenv>", kPublic },
|
|
{ "<tr1_impl/cinttypes>", kPrivate, "<cinttypes>", kPublic },
|
|
{ "<tr1_impl/cinttypes>", kPrivate, "<tr1/cinttypes>", kPublic },
|
|
{ "<tr1_impl/cmath>", kPrivate, "<cmath>", kPublic },
|
|
{ "<tr1_impl/cmath>", kPrivate, "<tr1/cmath>", kPublic },
|
|
{ "<tr1_impl/complex>", kPrivate, "<complex>", kPublic },
|
|
{ "<tr1_impl/complex>", kPrivate, "<tr1/complex>", kPublic },
|
|
{ "<tr1_impl/cstdint>", kPrivate, "<cstdint>", kPublic },
|
|
{ "<tr1_impl/cstdint>", kPrivate, "<tr1/cstdint>", kPublic },
|
|
{ "<tr1_impl/cstdio>", kPrivate, "<cstdio>", kPublic },
|
|
{ "<tr1_impl/cstdio>", kPrivate, "<tr1/cstdio>", kPublic },
|
|
{ "<tr1_impl/cstdlib>", kPrivate, "<cstdlib>", kPublic },
|
|
{ "<tr1_impl/cstdlib>", kPrivate, "<tr1/cstdlib>", kPublic },
|
|
{ "<tr1_impl/cwchar>", kPrivate, "<cwchar>", kPublic },
|
|
{ "<tr1_impl/cwchar>", kPrivate, "<tr1/cwchar>", kPublic },
|
|
{ "<tr1_impl/cwctype>", kPrivate, "<cwctype>", kPublic },
|
|
{ "<tr1_impl/cwctype>", kPrivate, "<tr1/cwctype>", kPublic },
|
|
{ "<tr1_impl/functional>", kPrivate, "<functional>", kPublic },
|
|
{ "<tr1_impl/functional>", kPrivate, "<tr1/functional>", kPublic },
|
|
{ "<tr1_impl/random>", kPrivate, "<random>", kPublic },
|
|
{ "<tr1_impl/random>", kPrivate, "<tr1/random>", kPublic },
|
|
{ "<tr1_impl/regex>", kPrivate, "<regex>", kPublic },
|
|
{ "<tr1_impl/regex>", kPrivate, "<tr1/regex>", kPublic },
|
|
{ "<tr1_impl/type_traits>", kPrivate, "<tr1/type_traits>", kPublic },
|
|
{ "<tr1_impl/type_traits>", kPrivate, "<type_traits>", kPublic },
|
|
{ "<tr1_impl/unordered_map>", kPrivate, "<tr1/unordered_map>", kPublic },
|
|
{ "<tr1_impl/unordered_map>", kPrivate, "<unordered_map>", kPublic },
|
|
{ "<tr1_impl/unordered_set>", kPrivate, "<tr1/unordered_set>", kPublic },
|
|
{ "<tr1_impl/unordered_set>", kPrivate, "<unordered_set>", kPublic },
|
|
{ "<tr1_impl/utility>", kPrivate, "<tr1/utility>", kPublic },
|
|
{ "<tr1_impl/utility>", kPrivate, "<utility>", kPublic },
|
|
// Hash and hashtable-based containers.
|
|
{ "<tr1_impl/functional_hash.h>", kPrivate, "<tr1/functional>", kPublic },
|
|
{ "<tr1_impl/functional_hash.h>", kPrivate, "<tr1/unordered_map>", kPublic },
|
|
{ "<tr1_impl/functional_hash.h>", kPrivate, "<tr1/unordered_set>", kPublic },
|
|
{ "<tr1/functional_hash.h>", kPrivate, "<tr1/unordered_map>", kPublic },
|
|
{ "<tr1/functional_hash.h>", kPrivate, "<tr1/unordered_set>", kPublic },
|
|
{ "<tr1_impl/hashtable>", kPrivate, "<tr1/unordered_map>", kPublic },
|
|
{ "<tr1_impl/hashtable>", kPrivate, "<tr1/unordered_set>", kPublic },
|
|
{ "<tr1/hashtable.h>", kPrivate, "<tr1/unordered_map>", kPublic },
|
|
{ "<tr1/hashtable.h>", kPrivate, "<tr1/unordered_set>", kPublic },
|
|
// All .tcc files are gcc internal-include files. We get them from
|
|
// ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && grep -R '^ *# *include.*tcc' * | perl -nle 'm/^([^:]+).*[<"]([^>"]+)[>"]/ && print qq@ { "<$2>", kPrivate, "<$1>", kPublic },@' | sort )
|
|
// I had to manually edit some of the entries to say the map-to is private.
|
|
{ "<bits/cmath.tcc>", kPrivate, "<cmath>", kPublic },
|
|
{ "<debug/safe_iterator.tcc>", kPrivate, "<debug/safe_iterator.h>", kPublic },
|
|
{ "<tr1_impl/random.tcc>", kPrivate, "<tr1_impl/random>", kPrivate },
|
|
// Some bits->bits #includes: A few files in bits re-export
|
|
// symbols from other files in bits.
|
|
// ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && grep '^ *# *include.*bits/' bits/* | perl -nle 'm/^([^:]+).*<([^>]+)>/ && print qq@ { "<$2>", kPrivate, "<$1>", kPrivate },@' | grep bits/ | sort -u)
|
|
// and carefully picked reasonable-looking results (algorithm
|
|
// *uses* pair but doesn't *re-export* pair, for instance).
|
|
{ "<bits/c++allocator.h>", kPrivate, "<bits/allocator.h>", kPrivate },
|
|
{ "<bits/ctype_base.h>", kPrivate, "<bits/locale_facets.h>", kPrivate },
|
|
{ "<bits/ctype_inline.h>", kPrivate, "<bits/locale_facets.h>", kPrivate },
|
|
{ "<bits/messages_members.h>", kPrivate,
|
|
"<bits/locale_facets_nonio.h>", kPrivate },
|
|
{ "<bits/stl_move.h>", kPrivate, "<bits/stl_algobase.h>", kPrivate },
|
|
// I don't think we want to be having people move to 'backward/'
|
|
// yet. (These hold deprecated STL classes that we still use
|
|
// actively.) These are the ones that turned up in an analysis of
|
|
{ "<backward/hash_fun.h>", kPrivate, "<hash_map>", kPublic },
|
|
{ "<backward/hash_fun.h>", kPrivate, "<hash_set>", kPublic },
|
|
{ "<backward/hashtable.h>", kPrivate, "<hash_map>", kPublic },
|
|
{ "<backward/hashtable.h>", kPrivate, "<hash_set>", kPublic },
|
|
{ "<backward/strstream>", kPrivate, "<strstream>", kPublic },
|
|
// We have backward as part of the -I search path now, so have the
|
|
// non-backwards-prefix version as well.
|
|
{ "<auto_ptr.h>", kPrivate, "<memory>", kPublic },
|
|
{ "<binders.h>", kPrivate, "<functional>", kPublic },
|
|
{ "<hash_fun.h>", kPrivate, "<hash_map>", kPublic },
|
|
{ "<hash_fun.h>", kPrivate, "<hash_set>", kPublic },
|
|
{ "<hashtable.h>", kPrivate, "<hash_map>", kPublic },
|
|
{ "<hashtable.h>", kPrivate, "<hash_set>", kPublic },
|
|
// (This one should perhaps be found automatically somehow.)
|
|
{ "<ext/sso_string_base.h>", kPrivate, "<string>", kPublic },
|
|
// The iostream .h files are confusing. Lots of private headers,
|
|
// which are handled above, but we also have public headers
|
|
// #including each other (eg <iostream> #includes <istream>). We
|
|
// are pretty forgiving: if a user specifies any public header, we
|
|
// generally don't require the others.
|
|
// ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && egrep '^ *# *include <(istream|ostream|iostream|fstream|sstream|streambuf|ios|iosfwd)>' *stream* ios | perl -nle 'm/^([^:]+).*[<"]([^>"]+)[>"]/ and print qq@ { "<$2>", kPublic, "<$1>", kPublic },@' | sort -u )
|
|
{ "<ios>", kPublic, "<istream>", kPublic },
|
|
{ "<ios>", kPublic, "<ostream>", kPublic },
|
|
{ "<iosfwd>", kPublic, "<ios>", kPublic },
|
|
{ "<iosfwd>", kPublic, "<streambuf>", kPublic },
|
|
{ "<istream>", kPublic, "<fstream>", kPublic },
|
|
{ "<istream>", kPublic, "<iostream>", kPublic },
|
|
{ "<istream>", kPublic, "<sstream>", kPublic },
|
|
{ "<ostream>", kPublic, "<fstream>", kPublic },
|
|
{ "<ostream>", kPublic, "<iostream>", kPublic },
|
|
{ "<ostream>", kPublic, "<istream>", kPublic },
|
|
{ "<ostream>", kPublic, "<sstream>", kPublic },
|
|
{ "<streambuf>", kPublic, "<ios>", kPublic },
|
|
// The location of exception_defines.h varies by GCC version. It should
|
|
// never be included directly.
|
|
{ "<exception_defines.h>", kPrivate, "<exception>", kPublic },
|
|
|
|
// post libstdc++-10 stuff which is not automatically caught by commands above
|
|
{ "<bits/exception.h>", kPrivate, "<exception>", kPublic },
|
|
{ "<pstl/execution_defs.h>", kPrivate, "<execution>", kPublic },
|
|
{ "<pstl/glue_algorithm_impl.h>", kPrivate, "<execution>", kPublic },
|
|
{ "<pstl/glue_execution_defs.h>", kPrivate, "<execution>", kPublic },
|
|
{ "<pstl/parallel_backend_tbb.h>", kPrivate, "<execution>", kPublic },
|
|
{ "<tbb/tbb_stddef.h>", kPrivate, "<execution>", kPublic },
|
|
};
|
|
|
|
// Returns true if str is a valid quoted filepath pattern (i.e. either
|
|
// a quoted filepath or "@" followed by a regex for matching a quoted
|
|
// filepath).
|
|
bool IsQuotedFilepathPattern(const string& str) {
|
|
return IsQuotedInclude(str) || StartsWith(str, "@");
|
|
}
|
|
|
|
// Given a vector of nodes, augment each node with its children, as
|
|
// defined by m: nodes[i] is replaced by nodes[i] + m[nodes[i]],
|
|
// ignoring duplicates. The input vector is modified in place.
|
|
void ExpandOnce(const IncludePicker::IncludeMap& m,
|
|
vector<MappedInclude>* nodes) {
|
|
vector<MappedInclude> nodes_and_children;
|
|
set<string> seen_nodes_and_children;
|
|
for (const MappedInclude& node : *nodes) {
|
|
// First insert the node itself, then all its kids.
|
|
if (!ContainsKey(seen_nodes_and_children, node.quoted_include)) {
|
|
nodes_and_children.push_back(node);
|
|
seen_nodes_and_children.insert(node.quoted_include);
|
|
}
|
|
if (const vector<MappedInclude>* children =
|
|
FindInMap(&m, node.quoted_include)) {
|
|
for (const MappedInclude& child : *children) {
|
|
if (!ContainsKey(seen_nodes_and_children, child.quoted_include)) {
|
|
nodes_and_children.push_back(child);
|
|
seen_nodes_and_children.insert(child.quoted_include);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
nodes->swap(nodes_and_children); // modify nodes in-place
|
|
}
|
|
|
|
enum TransitiveStatus { kUnused = 0, kCalculating, kDone };
|
|
|
|
// If the filename-map maps a.h to b.h, and also b.h to c.h, then
|
|
// there's a transitive mapping of a.h to c.h. We want to add that
|
|
// into the filepath map as well, to make lookups easier. We do this
|
|
// by doing a depth-first search for a single mapping, recursing
|
|
// whenever the value is itself a key in the map, and putting the
|
|
// results in a vector of all values seen.
|
|
// NOTE: This function updates values seen in filename_map, but
|
|
// does not invalidate any filename_map iterators.
|
|
void MakeNodeTransitive(IncludePicker::IncludeMap* filename_map,
|
|
map<string, TransitiveStatus>* seen_nodes,
|
|
vector<string>* node_stack, // used for debugging
|
|
const string& key) {
|
|
// If we've already calculated this node's transitive closure, we're done.
|
|
const TransitiveStatus status = (*seen_nodes)[key];
|
|
if (status == kCalculating) { // means there's a cycle in the mapping
|
|
// Note that cycles in mappings are generally benign, the cycle detection
|
|
// here is only necessary to protect the recursive algorithm from infinite
|
|
// regress. We will still expand all reachable nodes in the graph to a
|
|
// plain sequence representing the transitive closure.
|
|
// The expanded mappings are only used for simple lookup, never followed
|
|
// recursively (which could have necessitated preserving cycles and handling
|
|
// them in that traversal too).
|
|
// Log cycles at a high verbosity level to aid debugging.
|
|
VERRS(8) << "Ignored cycle in include mappings: ";
|
|
for (const string& node : *node_stack)
|
|
VERRS(8) << node << " -> ";
|
|
VERRS(8) << key << "\n";
|
|
return;
|
|
}
|
|
if (status == kDone)
|
|
return;
|
|
|
|
IncludePicker::IncludeMap::iterator node = filename_map->find(key);
|
|
if (node == filename_map->end()) {
|
|
(*seen_nodes)[key] = kDone;
|
|
return;
|
|
}
|
|
|
|
// Keep track of node->second as we update it, to avoid duplicates.
|
|
(*seen_nodes)[key] = kCalculating;
|
|
for (const MappedInclude& child : node->second) {
|
|
node_stack->push_back(child.quoted_include);
|
|
MakeNodeTransitive(filename_map, seen_nodes, node_stack,
|
|
child.quoted_include);
|
|
node_stack->pop_back();
|
|
}
|
|
(*seen_nodes)[key] = kDone;
|
|
|
|
// Our transitive closure is just the union of the closure of our
|
|
// children. This routine replaces our value with this closure,
|
|
// by replacing each of our values with its values. Since our
|
|
// values have already been made transitive, that is a closure.
|
|
ExpandOnce(*filename_map, &node->second);
|
|
}
|
|
|
|
// Updates the values in filename_map based on its transitive mappings.
|
|
void MakeMapTransitive(IncludePicker::IncludeMap* filename_map) {
|
|
// Insert keys of filename_map here once we know their value is
|
|
// the complete transitive closure.
|
|
map<string, TransitiveStatus> seen_nodes;
|
|
vector<string> node_stack;
|
|
for (const IncludePicker::IncludeMap::value_type& includes : *filename_map)
|
|
MakeNodeTransitive(filename_map, &seen_nodes, &node_stack, includes.first);
|
|
}
|
|
|
|
// Get a scalar value from a YAML node.
|
|
// Returns empty string if it's not of type ScalarNode.
|
|
string GetScalarValue(Node* node) {
|
|
ScalarNode* scalar = llvm::dyn_cast<ScalarNode>(node);
|
|
if (scalar == nullptr)
|
|
return string();
|
|
|
|
llvm::SmallString<8> storage;
|
|
return scalar->getValue(storage).str();
|
|
}
|
|
|
|
// Get a sequence value from a YAML node.
|
|
// Returns empty vector if it's not of type SequenceNode.
|
|
vector<string> GetSequenceValue(Node* node) {
|
|
vector<string> result;
|
|
|
|
SequenceNode* sequence = llvm::dyn_cast<SequenceNode>(node);
|
|
if (sequence != nullptr) {
|
|
for (Node& node : *sequence) {
|
|
result.push_back(GetScalarValue(&node));
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// If new_path doesn't already exist in search_path, makes a copy of search_path
|
|
// and adds new_path to it.
|
|
// Returns the original or extended search path.
|
|
vector<string> ExtendMappingFileSearchPath(const vector<string>& search_path,
|
|
const string& new_path) {
|
|
CHECK_(IsAbsolutePath(new_path));
|
|
|
|
if (std::find(search_path.begin(),
|
|
search_path.end(),
|
|
new_path) == search_path.end()) {
|
|
vector<string> extended(search_path);
|
|
extended.push_back(new_path);
|
|
return extended;
|
|
}
|
|
|
|
return search_path;
|
|
}
|
|
|
|
// Scans search_path for existing files with filename.
|
|
// If filename is absolute and exists, return it.
|
|
// If filename is relative and exists based on cwd, return it in absolute form.
|
|
// If filename is relative and doesn't exist, try to find it along search_path.
|
|
// Returns an absolute filename if file is found, otherwise filename untouched.
|
|
string FindFileInSearchPath(const vector<string>& search_path,
|
|
const string& filename) {
|
|
if (llvm::sys::fs::exists(filename)) {
|
|
// If the file exists, no matter if its path is relative or absolute,
|
|
// return it in absolute form.
|
|
return MakeAbsolutePath(filename);
|
|
} else if (!IsAbsolutePath(filename)) {
|
|
// If it's relative, scan search path.
|
|
for (const string& base_path : search_path) {
|
|
string candidate = MakeAbsolutePath(base_path, filename);
|
|
if (llvm::sys::fs::exists(candidate)) {
|
|
return candidate;
|
|
}
|
|
}
|
|
}
|
|
|
|
// This is proven not to exist, so handle the error when
|
|
// we attempt to open it.
|
|
return filename;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
MappedInclude::MappedInclude(const string& q, const string& p)
|
|
: quoted_include(q)
|
|
, path(p)
|
|
{
|
|
CHECK_(IsQuotedInclude(quoted_include)) <<
|
|
"Must be quoted include, was: " << quoted_include;
|
|
}
|
|
|
|
bool MappedInclude::HasAbsoluteQuotedInclude() const {
|
|
if (!StartsWith(quoted_include, "\"") || quoted_include.size() < 2) {
|
|
return false;
|
|
}
|
|
string path(quoted_include.begin() + 1, quoted_include.end() - 1);
|
|
return IsAbsolutePath(path);
|
|
}
|
|
|
|
IncludePicker::IncludePicker(bool no_default_mappings,
|
|
RegexDialect regex_dialect)
|
|
: has_called_finalize_added_include_lines_(false),
|
|
regex_dialect(regex_dialect) {
|
|
if (!no_default_mappings) {
|
|
AddDefaultMappings();
|
|
}
|
|
}
|
|
|
|
void IncludePicker::AddDefaultMappings() {
|
|
AddSymbolMappings(libc_symbol_map, IWYU_ARRAYSIZE(libc_symbol_map));
|
|
AddSymbolMappings(libstdcpp_symbol_map, IWYU_ARRAYSIZE(libstdcpp_symbol_map));
|
|
|
|
AddIncludeMappings(libc_include_map,
|
|
IWYU_ARRAYSIZE(libc_include_map));
|
|
AddIncludeMappings(stdlib_c_include_map,
|
|
IWYU_ARRAYSIZE(stdlib_c_include_map));
|
|
AddIncludeMappings(libstdcpp_include_map,
|
|
IWYU_ARRAYSIZE(libstdcpp_include_map));
|
|
|
|
AddPublicIncludes(stdlib_cpp_public_headers,
|
|
IWYU_ARRAYSIZE(stdlib_cpp_public_headers));
|
|
}
|
|
|
|
void IncludePicker::MarkVisibility(VisibilityMap* map,
|
|
const string& key,
|
|
IncludeVisibility visibility) {
|
|
CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore");
|
|
|
|
// insert() leaves any old value alone, and only inserts if the key is new.
|
|
map->insert(make_pair(key, visibility));
|
|
CHECK_((*map)[key] == visibility)
|
|
<< " Same file seen with two different visibilities: "
|
|
<< key
|
|
<< " Old vis: " << (*map)[key]
|
|
<< " New vis: " << visibility;
|
|
}
|
|
|
|
// AddDirectInclude lets us use some hard-coded rules to add filepath
|
|
// mappings at runtime. It includes, for instance, mappings from
|
|
// 'project/internal/foo.h' to 'project/public/foo_public.h' in google
|
|
// code (Google hides private headers in /internal/, much like glibc
|
|
// hides them in /bits/.)
|
|
void IncludePicker::AddDirectInclude(const string& includer_filepath,
|
|
const string& includee_filepath,
|
|
const string& quoted_include_as_written) {
|
|
CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore");
|
|
|
|
// Note: the includer may be a .cc file, which is unnecessary to add
|
|
// to our map, but harmless.
|
|
const string quoted_includer = ConvertToQuotedInclude(includer_filepath);
|
|
const string quoted_includee = ConvertToQuotedInclude(includee_filepath);
|
|
MappedInclude mapped_includer(quoted_includer, includer_filepath);
|
|
|
|
quoted_includes_to_quoted_includers_[quoted_includee].insert(quoted_includer);
|
|
const pair<string, string> key(includer_filepath, includee_filepath);
|
|
includer_and_includee_to_include_as_written_[key] = quoted_include_as_written;
|
|
|
|
// Mark the clang fake-file "<built-in>" as private, so we never try
|
|
// to map anything to it.
|
|
if (includer_filepath == "<built-in>")
|
|
MarkIncludeAsPrivate("\"<built-in>\"");
|
|
|
|
// Automatically mark files in foo/internal/bar as private, and map them.
|
|
// Then say that everyone else in foo/.* is a friend, who is allowed to
|
|
// include the otherwise-private header.
|
|
const size_t internal_pos = quoted_includee.find("internal/");
|
|
if (internal_pos != string::npos &&
|
|
(internal_pos == 0 || quoted_includee[internal_pos - 1] == '/')) {
|
|
MarkIncludeAsPrivate(quoted_includee);
|
|
// The second argument here is a regex for matching a quoted
|
|
// filepath. We get the opening quote from quoted_includee, and
|
|
// the closing quote as part of the .*.
|
|
AddFriendRegex(includee_filepath,
|
|
quoted_includee.substr(0, internal_pos) + ".*");
|
|
VERRS(8) << "Adding dynamic mapping for internal/ header\n";
|
|
AddMapping(quoted_includee, mapped_includer);
|
|
}
|
|
|
|
// Automatically mark <asm-FOO/bar.h> as private, and map to <asm/bar.h>.
|
|
if (StartsWith(quoted_includee, "<asm-")) {
|
|
MarkIncludeAsPrivate(quoted_includee);
|
|
string public_header = quoted_includee;
|
|
StripPast(&public_header, "/"); // read past "asm-whatever/"
|
|
public_header = "<asm/" + public_header; // now it's <asm/something.h>
|
|
VERRS(8) << "Adding dynamic mapping for <asm-*> header\n";
|
|
AddMapping(quoted_includee, MappedInclude(public_header));
|
|
}
|
|
}
|
|
|
|
void IncludePicker::AddMapping(const string& map_from,
|
|
const MappedInclude& map_to) {
|
|
VERRS(8) << "Adding mapping from " << map_from << " to "
|
|
<< map_to.quoted_include << "\n";
|
|
CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore");
|
|
CHECK_(IsQuotedFilepathPattern(map_from)
|
|
&& "All map keys must be quoted filepaths or @ followed by regex");
|
|
filepath_include_map_[map_from].push_back(map_to);
|
|
}
|
|
|
|
void IncludePicker::AddIncludeMapping(const string& map_from,
|
|
IncludeVisibility from_visibility,
|
|
const MappedInclude& map_to,
|
|
IncludeVisibility to_visibility) {
|
|
AddMapping(map_from, map_to);
|
|
MarkVisibility(&include_visibility_map_, map_from, from_visibility);
|
|
MarkVisibility(&include_visibility_map_, map_to.quoted_include,
|
|
to_visibility);
|
|
}
|
|
|
|
void IncludePicker::AddSymbolMapping(const string& map_from,
|
|
const MappedInclude& map_to,
|
|
IncludeVisibility to_visibility) {
|
|
symbol_include_map_[map_from].push_back(map_to);
|
|
|
|
MarkVisibility(&include_visibility_map_, map_to.quoted_include,
|
|
to_visibility);
|
|
}
|
|
|
|
void IncludePicker::AddIncludeMappings(const IncludeMapEntry* entries,
|
|
size_t count) {
|
|
for (size_t i = 0; i < count; ++i) {
|
|
const IncludeMapEntry& e = entries[i];
|
|
AddIncludeMapping(e.map_from, e.from_visibility, MappedInclude(e.map_to),
|
|
e.to_visibility);
|
|
}
|
|
}
|
|
|
|
void IncludePicker::AddSymbolMappings(const IncludeMapEntry* entries,
|
|
size_t count) {
|
|
for (size_t i = 0; i < count; ++i) {
|
|
const IncludeMapEntry& e = entries[i];
|
|
AddSymbolMapping(e.map_from, MappedInclude(e.map_to), e.to_visibility);
|
|
}
|
|
}
|
|
|
|
void IncludePicker::AddPublicIncludes(const char** includes, size_t count) {
|
|
for (size_t i = 0; i < count; ++i) {
|
|
const char* include = includes[i];
|
|
MarkVisibility(&include_visibility_map_, include, kPublic);
|
|
}
|
|
}
|
|
|
|
void IncludePicker::MarkIncludeAsPrivate(
|
|
const string& quoted_filepath_pattern) {
|
|
CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore");
|
|
CHECK_(IsQuotedFilepathPattern(quoted_filepath_pattern)
|
|
&& "MIAP takes a quoted filepath pattern");
|
|
MarkVisibility(&include_visibility_map_, quoted_filepath_pattern, kPrivate);
|
|
}
|
|
|
|
void IncludePicker::MarkPathAsPrivate(const string& path) {
|
|
CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore");
|
|
MarkVisibility(&path_visibility_map_, path, kPrivate);
|
|
}
|
|
|
|
void IncludePicker::AddFriendRegex(const string& includee_filepath,
|
|
const string& quoted_friend_regex) {
|
|
friend_to_headers_map_["@" + quoted_friend_regex].insert(includee_filepath);
|
|
}
|
|
|
|
namespace {
|
|
|
|
// Given a map keyed by quoted filepath patterns, return a vector
|
|
// containing the @-regexes among the keys.
|
|
template <typename MapType>
|
|
vector<string> ExtractKeysMarkedAsRegexes(const MapType& m) {
|
|
vector<string> regex_keys;
|
|
for (const typename MapType::value_type& item : m) {
|
|
if (StartsWith(item.first, "@"))
|
|
regex_keys.push_back(item.first);
|
|
}
|
|
return regex_keys;
|
|
}
|
|
|
|
bool ContainsQuotedInclude(
|
|
const vector<MappedInclude>& mapped_includes,
|
|
const string& quoted_include) {
|
|
for (const MappedInclude& mapped : mapped_includes) {
|
|
if (mapped.quoted_include == quoted_include) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
} // anonymous namespace
|
|
|
|
// Expands the regex keys in filepath_include_map_ and
|
|
// friend_to_headers_map_ by matching them against all source files
|
|
// seen by iwyu. For each include that matches the regex, we add it
|
|
// to the map by copying the regex entry and replacing the key with
|
|
// the seen #include.
|
|
void IncludePicker::ExpandRegexes() {
|
|
// First, get the regex keys.
|
|
const vector<string> filepath_include_map_regex_keys =
|
|
ExtractKeysMarkedAsRegexes(filepath_include_map_);
|
|
const vector<string> friend_to_headers_map_regex_keys =
|
|
ExtractKeysMarkedAsRegexes(friend_to_headers_map_);
|
|
|
|
// Then, go through all #includes to see if they match the regexes,
|
|
// discarding the identity mappings. TODO(wan): to improve
|
|
// performance, don't construct more than one Regex object for each
|
|
// element in the above vectors.
|
|
for (const auto& incmap : quoted_includes_to_quoted_includers_) {
|
|
const string& hdr = incmap.first;
|
|
for (const string& regex_key : filepath_include_map_regex_keys) {
|
|
const string regex = regex_key.substr(1);
|
|
const vector<MappedInclude>& map_to = filepath_include_map_[regex_key];
|
|
if (RegexMatch(regex_dialect, hdr, regex) &&
|
|
!ContainsQuotedInclude(map_to, hdr)) {
|
|
for (const MappedInclude& target : map_to) {
|
|
filepath_include_map_[hdr].push_back(MappedInclude(
|
|
RegexReplace(regex_dialect, hdr, regex, target.quoted_include)));
|
|
}
|
|
MarkVisibility(&include_visibility_map_, hdr,
|
|
include_visibility_map_[regex_key]);
|
|
}
|
|
}
|
|
for (const string& regex_key : friend_to_headers_map_regex_keys) {
|
|
if (RegexMatch(regex_dialect, hdr, regex_key.substr(1))) {
|
|
InsertAllInto(friend_to_headers_map_[regex_key],
|
|
&friend_to_headers_map_[hdr]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Handle work that's best done after we've seen all the mappings
|
|
// (including dynamically-added ones) and all the include files.
|
|
// For instance, we can now expand all the regexes we've seen in
|
|
// the mapping-keys, since we have the full list of #includes to
|
|
// match them again. We also transitively-close the maps.
|
|
void IncludePicker::FinalizeAddedIncludes() {
|
|
CHECK_(!has_called_finalize_added_include_lines_ && "Can't call FAI twice");
|
|
|
|
// The map keys may be regular expressions.
|
|
// Match those to seen #includes now.
|
|
ExpandRegexes();
|
|
|
|
// If a.h maps to b.h maps to c.h, we'd like an entry from a.h to c.h too.
|
|
MakeMapTransitive(&filepath_include_map_);
|
|
// Now that filepath_include_map_ is transitively closed, it's an
|
|
// easy task to get the values of symbol_include_map_ closed too.
|
|
for (IncludeMap::value_type& symbol_include : symbol_include_map_) {
|
|
ExpandOnce(filepath_include_map_, &symbol_include.second);
|
|
}
|
|
|
|
has_called_finalize_added_include_lines_ = true;
|
|
}
|
|
|
|
// For the given key, return the vector of values associated with that
|
|
// key, or an empty vector if the key does not exist in the map.
|
|
// *However*, we filter out all values that have private visibility
|
|
// before returning the vector. *Also*, if the key is public in
|
|
// the map, we insert the key as the first of the returned values,
|
|
// this is an implicit "self-map."
|
|
vector<MappedInclude> IncludePicker::GetPublicValues(
|
|
const IncludePicker::IncludeMap& m, const string& key) const {
|
|
CHECK_(!StartsWith(key, "@"));
|
|
vector<MappedInclude> retval;
|
|
const vector<MappedInclude>* values = FindInMap(&m, key);
|
|
if (!values || values->empty())
|
|
return retval;
|
|
|
|
for (const MappedInclude& value : *values) {
|
|
CHECK_(!StartsWith(value.quoted_include, "@"));
|
|
if (GetVisibility(value, kPublic) == kPublic)
|
|
retval.push_back(value);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
string IncludePicker::MaybeGetIncludeNameAsWritten(
|
|
const string& includer_filepath, const string& includee_filepath) const {
|
|
const pair<string, string> key(includer_filepath, includee_filepath);
|
|
// I want to use GetOrDefault here, but it has trouble deducing tpl args.
|
|
const string* value = FindInMap(&includer_and_includee_to_include_as_written_,
|
|
key);
|
|
return value ? *value : "";
|
|
}
|
|
|
|
vector<string> IncludePicker::BestQuotedIncludesForIncluder(
|
|
const vector<MappedInclude>& includes,
|
|
const string& including_filepath) const {
|
|
// Convert each MappedInclude to a quoted include, according to the
|
|
// following priorities:
|
|
// 1. If the file is already included, use whatever name it's already
|
|
// included via. This is better to use than ConvertToQuotedInclude
|
|
// because it avoids trouble when the same file is accessible via
|
|
// different include search-paths, or is accessed via a symlink.
|
|
// 2. If the quoted include in the MappedInclude object is an absolute path,
|
|
// that's unlikely to be what's wanted. Try to convert it to a relative
|
|
// include via ConvertToQuotedInclude.
|
|
// 3. Otherwise, use the quoted include present in the MappedInclude.
|
|
const string including_path =
|
|
MakeAbsolutePath(GetParentPath(including_filepath));
|
|
vector<string> retval;
|
|
for (const MappedInclude& mapped_include : includes) {
|
|
const string& quoted_include_as_written =
|
|
MaybeGetIncludeNameAsWritten(including_filepath, mapped_include.path);
|
|
if (!quoted_include_as_written.empty()) {
|
|
retval.push_back(quoted_include_as_written);
|
|
} else if (mapped_include.HasAbsoluteQuotedInclude() &&
|
|
!mapped_include.path.empty()) {
|
|
retval.push_back(ConvertToQuotedInclude(mapped_include.path,
|
|
including_path));
|
|
} else {
|
|
retval.push_back(mapped_include.quoted_include);
|
|
}
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
vector<MappedInclude> IncludePicker::GetCandidateHeadersForSymbol(
|
|
const string& symbol) const {
|
|
CHECK_(has_called_finalize_added_include_lines_ && "Must finalize includes");
|
|
return GetPublicValues(symbol_include_map_, symbol);
|
|
}
|
|
|
|
vector<string> IncludePicker::GetCandidateHeadersForSymbolUsedFrom(
|
|
const string& symbol, const string& including_filepath) const {
|
|
return BestQuotedIncludesForIncluder(
|
|
GetCandidateHeadersForSymbol(symbol), including_filepath);
|
|
}
|
|
|
|
vector<MappedInclude> IncludePicker::GetCandidateHeadersForFilepath(
|
|
const string& filepath, const string& including_filepath) const {
|
|
CHECK_(has_called_finalize_added_include_lines_ && "Must finalize includes");
|
|
string absolute_quoted_header = ConvertToQuotedInclude(filepath);
|
|
vector<MappedInclude> retval =
|
|
GetPublicValues(filepath_include_map_, absolute_quoted_header);
|
|
|
|
// We also need to consider the header itself. Make that an option if it's
|
|
// public or there's no other option.
|
|
string quoted_header;
|
|
if (including_filepath.empty()) {
|
|
quoted_header = absolute_quoted_header;
|
|
} else {
|
|
quoted_header = ConvertToQuotedInclude(
|
|
filepath, MakeAbsolutePath(GetParentPath(including_filepath)));
|
|
}
|
|
MappedInclude default_header(quoted_header, filepath);
|
|
if (retval.empty() || GetVisibility(default_header, kPublic) == kPublic) {
|
|
// Insert at front so it's the preferred option
|
|
retval.insert(retval.begin(), default_header);
|
|
}
|
|
return retval;
|
|
}
|
|
|
|
// Except for the case that the includer is a 'friend' of the includee
|
|
// (via an '// IWYU pragma: friend XXX'), the same as
|
|
// GetCandidateHeadersForFilepath.
|
|
vector<string> IncludePicker::GetCandidateHeadersForFilepathIncludedFrom(
|
|
const string& included_filepath, const string& including_filepath) const {
|
|
vector<MappedInclude> mapped_includes;
|
|
// We pass the own files path to ConvertToQuotedInclude so the quoted include
|
|
// for the case that there is no matching `-I` option is just the filename
|
|
// (e.g. "foo.cpp") instead of the absolute file path.
|
|
const string including_path =
|
|
MakeAbsolutePath(GetParentPath(including_filepath));
|
|
const string quoted_includer = ConvertToQuotedInclude(
|
|
including_filepath, including_path);
|
|
const string quoted_includee = ConvertToQuotedInclude(
|
|
included_filepath, including_path);
|
|
const set<string>* headers_with_includer_as_friend =
|
|
FindInMap(&friend_to_headers_map_, quoted_includer);
|
|
if (headers_with_includer_as_friend != nullptr &&
|
|
ContainsKey(*headers_with_includer_as_friend, included_filepath)) {
|
|
mapped_includes.push_back(
|
|
MappedInclude(quoted_includee, including_filepath));
|
|
} else {
|
|
mapped_includes =
|
|
GetCandidateHeadersForFilepath(included_filepath, including_filepath);
|
|
if (mapped_includes.size() == 1) {
|
|
if (GetVisibility(mapped_includes[0]) == kPrivate) {
|
|
VERRS(0) << "Warning: "
|
|
<< "No public header found to replace the private header "
|
|
<< included_filepath << "\n";
|
|
}
|
|
}
|
|
}
|
|
|
|
return BestQuotedIncludesForIncluder(mapped_includes, including_filepath);
|
|
}
|
|
|
|
bool IncludePicker::HasMapping(const string& map_from_filepath,
|
|
const string& map_to_filepath) const {
|
|
CHECK_(has_called_finalize_added_include_lines_ && "Must finalize includes");
|
|
const string quoted_from = ConvertToQuotedInclude(map_from_filepath);
|
|
const string quoted_to = ConvertToQuotedInclude(map_to_filepath);
|
|
// We can't use GetCandidateHeadersForFilepath since includer might be private
|
|
const vector<MappedInclude>* all_mappers =
|
|
FindInMap(&filepath_include_map_, quoted_from);
|
|
if (all_mappers) {
|
|
if (ContainsQuotedInclude(*all_mappers, quoted_to)) {
|
|
return true;
|
|
}
|
|
}
|
|
return quoted_to == quoted_from; // indentity mapping, why not?
|
|
}
|
|
|
|
bool IncludePicker::IsPublic(const clang::FileEntry* file) const {
|
|
CHECK_(file && "Need existing FileEntry");
|
|
const string path = GetFilePath(file);
|
|
const string quoted_file = ConvertToQuotedInclude(path);
|
|
const MappedInclude include(quoted_file, path);
|
|
return (GetVisibility(include) == kPublic);
|
|
}
|
|
|
|
// Parses a YAML/JSON file containing mapping directives of various types.
|
|
void IncludePicker::AddMappingsFromFile(const string& filename) {
|
|
vector<string> default_search_path;
|
|
return AddMappingsFromFile(filename, default_search_path);
|
|
}
|
|
|
|
// Parses a YAML/JSON file containing mapping directives of various types:
|
|
// symbol - symbol name -> quoted include
|
|
// include - private quoted include -> public quoted include
|
|
// ref - include mechanism for mapping files, to allow project-specific
|
|
// groupings
|
|
// This private implementation method is recursive and builds the search path
|
|
// incrementally.
|
|
void IncludePicker::AddMappingsFromFile(const string& filename,
|
|
const vector<string>& search_path) {
|
|
string absolute_path = FindFileInSearchPath(search_path, filename);
|
|
|
|
llvm::ErrorOr<unique_ptr<MemoryBuffer>> bufferOrError =
|
|
MemoryBuffer::getFile(absolute_path);
|
|
if (std::error_code error = bufferOrError.getError()) {
|
|
VERRS(0) << "Cannot open mapping file '" << absolute_path
|
|
<< "': " << error.message() << ".\n";
|
|
return;
|
|
}
|
|
|
|
VERRS(5) << "Adding mappings from file '" << absolute_path << "'.\n";
|
|
|
|
SourceMgr source_manager;
|
|
Stream json_stream(bufferOrError.get()->getMemBufferRef(), source_manager);
|
|
|
|
document_iterator stream_begin = json_stream.begin();
|
|
if (stream_begin == json_stream.end())
|
|
return;
|
|
|
|
// Get root sequence.
|
|
Node* root = stream_begin->getRoot();
|
|
SequenceNode *array = llvm::dyn_cast<SequenceNode>(root);
|
|
if (array == nullptr) {
|
|
json_stream.printError(root, "Root element must be an array.");
|
|
return;
|
|
}
|
|
|
|
for (Node& array_item_node : *array) {
|
|
Node* current_node = &array_item_node;
|
|
|
|
// Every item must be a JSON object ("mapping" in YAML terms.)
|
|
MappingNode* mapping = llvm::dyn_cast<MappingNode>(current_node);
|
|
if (mapping == nullptr) {
|
|
json_stream.printError(current_node,
|
|
"Mapping directives must be objects.");
|
|
return;
|
|
}
|
|
|
|
for (KeyValueNode &mapping_item_node : *mapping) {
|
|
// General form is { directive: <data> }.
|
|
const string directive = GetScalarValue(mapping_item_node.getKey());
|
|
|
|
if (directive == "symbol") {
|
|
// Symbol mapping.
|
|
vector<string> mapping = GetSequenceValue(mapping_item_node.getValue());
|
|
if (mapping.size() != 4) {
|
|
json_stream.printError(current_node,
|
|
"Symbol mapping expects a value on the form "
|
|
"'[from, visibility, to, visibility]'.");
|
|
return;
|
|
}
|
|
|
|
// Ignore unused from-visibility, at some point maybe remove it from the
|
|
// mapping file format.
|
|
|
|
IncludeVisibility to_visibility = ParseVisibility(mapping[3]);
|
|
if (to_visibility == kUnusedVisibility) {
|
|
json_stream.printError(current_node,
|
|
"Unknown visibility '" + mapping[3] + "'.");
|
|
return;
|
|
}
|
|
|
|
if (!IsQuotedInclude(mapping[2])) {
|
|
json_stream.printError(
|
|
current_node,
|
|
"Expected to-entry to be quoted include, but was '" + mapping[2] +
|
|
"'");
|
|
return;
|
|
}
|
|
|
|
AddSymbolMapping(mapping[0], MappedInclude(mapping[2]), to_visibility);
|
|
} else if (directive == "include") {
|
|
// Include mapping.
|
|
vector<string> mapping = GetSequenceValue(mapping_item_node.getValue());
|
|
if (mapping.size() != 4) {
|
|
json_stream.printError(current_node,
|
|
"Include mapping expects a value on the form "
|
|
"'[from, visibility, to, visibility]'.");
|
|
return;
|
|
}
|
|
|
|
IncludeVisibility from_visibility = ParseVisibility(mapping[1]);
|
|
if (from_visibility == kUnusedVisibility) {
|
|
json_stream.printError(current_node,
|
|
"Unknown visibility '" + mapping[1] + "'.");
|
|
return;
|
|
}
|
|
|
|
IncludeVisibility to_visibility = ParseVisibility(mapping[3]);
|
|
if (to_visibility == kUnusedVisibility) {
|
|
json_stream.printError(current_node,
|
|
"Unknown visibility '" + mapping[3] + "'.");
|
|
return;
|
|
}
|
|
|
|
if (!IsQuotedFilepathPattern(mapping[0])) {
|
|
json_stream.printError(
|
|
current_node,
|
|
"Expected from-entry to be quoted filepath or @regex, but was '" +
|
|
mapping[0] + "'");
|
|
return;
|
|
}
|
|
|
|
if (!IsQuotedInclude(mapping[2])) {
|
|
json_stream.printError(
|
|
current_node,
|
|
"Expected to-entry to be quoted include, but was '" + mapping[2] +
|
|
"'");
|
|
return;
|
|
}
|
|
|
|
AddIncludeMapping(mapping[0],
|
|
from_visibility,
|
|
MappedInclude(mapping[2]),
|
|
to_visibility);
|
|
} else if (directive == "ref") {
|
|
// Mapping ref.
|
|
string ref_file = GetScalarValue(mapping_item_node.getValue());
|
|
if (ref_file.empty()) {
|
|
json_stream.printError(current_node,
|
|
"Mapping ref expects a single filename value.");
|
|
return;
|
|
}
|
|
|
|
// Add the path of the file we're currently processing
|
|
// to the search path. Allows refs to be relative to referrer.
|
|
vector<string> extended_search_path =
|
|
ExtendMappingFileSearchPath(search_path,
|
|
GetParentPath(absolute_path));
|
|
|
|
// Recurse.
|
|
AddMappingsFromFile(ref_file, extended_search_path);
|
|
} else {
|
|
json_stream.printError(current_node,
|
|
"Unknown directive '" + directive + "'.");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
IncludeVisibility IncludePicker::ParseVisibility(
|
|
const string& visibility) const {
|
|
if (visibility == "private")
|
|
return kPrivate;
|
|
else if (visibility == "public")
|
|
return kPublic;
|
|
|
|
return kUnusedVisibility;
|
|
}
|
|
|
|
IncludeVisibility IncludePicker::GetVisibility(
|
|
const MappedInclude& include, IncludeVisibility default_value) const {
|
|
const IncludeVisibility* include_visibility =
|
|
FindInMap(&include_visibility_map_, include.quoted_include);
|
|
if (include_visibility) {
|
|
return *include_visibility;
|
|
}
|
|
return GetOrDefault(path_visibility_map_, include.path, default_value);
|
|
}
|
|
|
|
} // namespace include_what_you_use
|