You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2116 lines
90 KiB
Diff

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 1f06014..dce8632 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -15,7 +15,7 @@ jobs:
fail-fast: false
env:
- LLVM_TAG: -12
+ LLVM_TAG:
steps:
- name: Install prerequisites
@@ -33,6 +33,10 @@ jobs:
sudo apt install -y libclang$LLVM_TAG-dev
sudo apt install -y clang$LLVM_TAG
+ - name: Broken packaging workaround
+ run: |
+ sudo touch /usr/lib/llvm-14/lib/libclang-14.so.14.0.0
+
- name: Check out default branch
uses: actions/checkout@v2
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 923b4d9..0a0d683 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -68,9 +68,9 @@ endif()
set(LLVM_LINK_COMPONENTS
Option
Support
- X86AsmParser
- X86Desc
- X86Info
+ AllTargetsAsmParsers
+ AllTargetsDescs
+ AllTargetsInfos
)
add_llvm_executable(include-what-you-use
@@ -110,8 +110,8 @@ if (MSVC)
-D_HAS_EXCEPTIONS=0
)
- # Enable bigobj support and sane C++ exception semantics.
- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /EHsc")
+ # Enable bigobj support
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj")
endif()
# Link dynamically or statically depending on user preference.
diff --git a/README.md b/README.md
index 58abdc7..0ef3082 100644
--- a/README.md
+++ b/README.md
@@ -40,6 +40,7 @@ We assume you already have compiled LLVM and Clang libraries on your system, eit
| 9 | 0.13 | `clang_9.0` |
| 10 | 0.14 | `clang_10` |
| 11 | 0.15 | `clang_11` |
+| 12 | 0.16 | `clang_12` |
| ... | ... | ... |
| main | | `master` |
@@ -142,7 +143,7 @@ Note that with Microsoft's Visual C++ compiler, IWYU needs the `--driver-mode=cl
#### Using with a compilation database ####
-The `iwyu_tool.py` script predates the native CMake support, and works off the [compilation database format](https://clang.llvm.org/docs/JSONCompilationDatabase.html). For example, CMake generates such a database named `compile_commands.json` with the `CMAKE_EXPORT_COMPILE_COMMANDS` option enabled.
+The `iwyu_tool.py` script pre-dates the native CMake support, and works off the [compilation database format](https://clang.llvm.org/docs/JSONCompilationDatabase.html). For example, CMake generates such a database named `compile_commands.json` with the `CMAKE_EXPORT_COMPILE_COMMANDS` option enabled.
The script's command-line syntax is designed to mimic Clang's LibTooling, but they are otherwise unrelated. It can be used like this:
diff --git a/fix_includes.py b/fix_includes.py
index 7600361..8de5775 100755
--- a/fix_includes.py
+++ b/fix_includes.py
@@ -2309,11 +2309,12 @@ def ProcessIWYUOutput(f, files_to_process, flags, cwd):
# seen for them. (We have to wait until we're all done, since a .h
# file may have a contentful change when #included from one .cc
# file, but not another, and we need to have merged them above.)
- for filename in iwyu_output_records:
- if not iwyu_output_records[filename].HasContentfulChanges():
- print('(skipping %s: iwyu reports no contentful changes)' % filename)
- # Mark that we're skipping this file by setting the record to None
- iwyu_output_records[filename] = None
+ if not flags.update_comments:
+ for filename in iwyu_output_records:
+ if not iwyu_output_records[filename].HasContentfulChanges():
+ print('(skipping %s: iwyu reports no contentful changes)' % filename)
+ # Mark that we're skipping this file by setting the record to None
+ iwyu_output_records[filename] = None
# Now do all the fixing, and return the number of files modified
contentful_records = [ior for ior in iwyu_output_records.values() if ior]
@@ -2373,6 +2374,12 @@ def main(argv):
help='Put comments after the #include lines')
parser.add_option('--nocomments', action='store_false', dest='comments')
+ parser.add_option('--update_comments', action='store_true', default=False,
+ help=('Update #include comments, even if no #include lines'
+ ' are added or removed'))
+ parser.add_option('--noupdate_comments', action='store_false',
+ dest='update_comments')
+
parser.add_option('--safe_headers', action='store_true', default=True,
help=('Do not remove unused #includes/fwd-declares from'
' header files; just add new ones [default]'))
@@ -2440,6 +2447,9 @@ def main(argv):
not flags.separate_project_includes.endswith('/')):
flags.separate_project_includes += os.path.sep
+ if flags.update_comments:
+ flags.comments = True
+
if flags.sort_only:
if not files_to_modify:
sys.exit('FATAL ERROR: -s flag requires a list of filenames')
diff --git a/fix_includes_test.py b/fix_includes_test.py
index 380da54..07bd78d 100755
--- a/fix_includes_test.py
+++ b/fix_includes_test.py
@@ -34,6 +34,7 @@ class FakeFlags(object):
def __init__(self):
self.blank_lines = False
self.comments = True
+ self.update_comments = False
self.dry_run = False
self.ignore_re = None
self.only_re = None
@@ -1916,6 +1917,54 @@ The full include-list for subdir/include_comments.cc:
self.RegisterFileContents({'subdir/include_comments.cc': infile})
self.ProcessAndTest(iwyu_output)
+ def testUpdateCommentsFlag(self):
+ """Tests we update comments with --update_comments."""
+ self.flags.update_comments = True
+ infile = """\
+#include "must_keep.h" // IWYU pragma: keep
+#include "used.h" // for SomethingElse ///-
+///+#include "used.h" // for Used
+
+Used used;
+int main() { return 0; }
+"""
+ iwyu_output = """\
+subdir/include_comments.cc should add these lines:
+
+subdir/include_comments.cc should remove these lines:
+
+The full include-list for subdir/include_comments.cc:
+#include "must_keep.h"
+#include "used.h" // for Used
+---
+"""
+ self.RegisterFileContents({'subdir/include_comments.cc': infile})
+ self.ProcessAndTest(iwyu_output)
+
+ def testNoUpdateCommentsFlag(self):
+ """Tests we don't update comments with --noupdate_comments."""
+ self.flags.update_comments = False
+ infile = """\
+#include "must_keep.h" // IWYU pragma: keep
+#include "used.h" // for SomethingElse
+
+Used used;
+int main() { return 0; }
+"""
+ iwyu_output = """\
+subdir/include_comments.cc should add these lines:
+
+subdir/include_comments.cc should remove these lines:
+
+The full include-list for subdir/include_comments.cc:
+#include "must_keep.h"
+#include "used.h" // for Used
+---
+"""
+ self.RegisterFileContents({'subdir/include_comments.cc': infile})
+ self.ProcessAndTest(iwyu_output,
+ unedited_files=['subdir/include_comments.cc'])
+
def testFixingTwoFiles(self):
"""Make sure data for one fix doesn't overlap with a second."""
file_a = """\
diff --git a/gcc.symbols.imp b/gcc.symbols.imp
index 5ecf219..de38147 100644
--- a/gcc.symbols.imp
+++ b/gcc.symbols.imp
@@ -9,22 +9,36 @@
# 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 private.
+# equal. The same goes for <stdint.h>. The visibility on the
+# symbol-name is ignored; by convention we always set it to private.
[
- { symbol: [ "blksize_t", private, "<sys/types.h>", public ] },
- { symbol: [ "blkcnt_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "aiocb", private, "<aio.h>", public ] },
{ symbol: [ "blkcnt_t", private, "<sys/types.h>", public ] },
+ { symbol: [ "blkcnt_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "blksize_t", private, "<sys/types.h>", public ] },
{ symbol: [ "blksize_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "cc_t", private, "<termios.h>", public ] },
{ symbol: [ "clock_t", private, "<sys/types.h>", public ] },
+ { symbol: [ "clock_t", private, "<sys/time.h>", public ] },
{ symbol: [ "clock_t", private, "<time.h>", public ] },
+ { symbol: [ "clockid_t", private, "<sys/types.h>", public ] },
+ { symbol: [ "clockid_t", private, "<time.h>", public ] },
{ symbol: [ "daddr_t", private, "<sys/types.h>", public ] },
{ symbol: [ "daddr_t", private, "<rpc/types.h>", public ] },
{ symbol: [ "dev_t", private, "<sys/types.h>", public ] },
{ symbol: [ "dev_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "div_t", private, "<stdlib.h>", public ] },
+ { symbol: [ "double_t", private, "<math.h>", public ] },
{ symbol: [ "error_t", private, "<errno.h>", public ] },
{ symbol: [ "error_t", private, "<argp.h>", public ] },
{ symbol: [ "error_t", private, "<argz.h>", public ] },
+ { symbol: [ "fd_set", private, "<sys/select.h>", public ] },
+ { symbol: [ "fd_set", private, "<sys/time.h>", public ] },
+ { symbol: [ "fenv_t", private, "<fenv.h>", public ] },
+ { symbol: [ "fexcept_t", private, "<fenv.h>", public ] },
+ { symbol: [ "FILE", private, "<stdio.h>", public ] },
+ { symbol: [ "FILE", private, "<wchar.h>", public ] },
+ { symbol: [ "float_t", private, "<math.h>", public ] },
{ symbol: [ "fsblkcnt_t", private, "<sys/types.h>", public ] },
{ symbol: [ "fsblkcnt_t", private, "<sys/statvfs.h>", public ] },
{ symbol: [ "fsfilcnt_t", private, "<sys/types.h>", public ] },
@@ -32,91 +46,173 @@
{ symbol: [ "gid_t", private, "<sys/types.h>", public ] },
{ symbol: [ "gid_t", private, "<grp.h>", public ] },
{ symbol: [ "gid_t", private, "<pwd.h>", public ] },
+ { symbol: [ "gid_t", private, "<signal.h>", public ] },
{ symbol: [ "gid_t", private, "<stropts.h>", public ] },
{ symbol: [ "gid_t", private, "<sys/ipc.h>", public ] },
{ symbol: [ "gid_t", private, "<sys/stat.h>", public ] },
{ symbol: [ "gid_t", private, "<unistd.h>", public ] },
{ symbol: [ "id_t", private, "<sys/types.h>", public ] },
{ symbol: [ "id_t", private, "<sys/resource.h>", public ] },
+ { symbol: [ "imaxdiv_t", private, "<inttypes.h>", public ] },
+ { symbol: [ "intmax_t", private, "<stdint.h>", public ] },
+ { symbol: [ "intmax_t", private, "<inttypes.h>", public ] },
+ { symbol: [ "uintmax_t", private, "<stdint.h>", public ] },
+ { symbol: [ "uintmax_t", private, "<inttypes.h>", public ] },
{ symbol: [ "ino64_t", private, "<sys/types.h>", public ] },
{ symbol: [ "ino64_t", private, "<dirent.h>", public ] },
{ symbol: [ "ino_t", private, "<sys/types.h>", public ] },
{ symbol: [ "ino_t", private, "<dirent.h>", public ] },
{ symbol: [ "ino_t", private, "<sys/stat.h>", public ] },
- { symbol: [ "int8_t", private, "<sys/types.h>", public ] },
{ symbol: [ "int8_t", private, "<stdint.h>", public ] },
+ { symbol: [ "int8_t", private, "<inttypes.h>", public ] },
{ symbol: [ "int16_t", private, "<stdint.h>", public ] },
+ { symbol: [ "int16_t", private, "<inttypes.h>", public ] },
{ symbol: [ "int32_t", private, "<stdint.h>", public ] },
+ { symbol: [ "int32_t", private, "<inttypes.h>", public ] },
{ symbol: [ "int64_t", private, "<stdint.h>", public ] },
+ { symbol: [ "int64_t", private, "<inttypes.h>", public ] },
{ symbol: [ "uint8_t", private, "<stdint.h>", public ] },
+ { symbol: [ "uint8_t", private, "<inttypes.h>", public ] },
{ symbol: [ "uint16_t", private, "<stdint.h>", public ] },
+ { symbol: [ "uint16_t", private, "<inttypes.h>", public ] },
{ symbol: [ "uint32_t", private, "<stdint.h>", public ] },
+ { symbol: [ "uint32_t", private, "<inttypes.h>", public ] },
{ symbol: [ "uint64_t", private, "<stdint.h>", public ] },
+ { symbol: [ "uint64_t", private, "<inttypes.h>", public ] },
{ symbol: [ "intptr_t", private, "<stdint.h>", public ] },
+ { symbol: [ "intptr_t", private, "<inttypes.h>", public ] },
{ symbol: [ "uintptr_t", private, "<stdint.h>", public ] },
- { symbol: [ "intptr_t", private, "<unistd.h>", public ] },
+ { symbol: [ "uintptr_t", private, "<inttypes.h>", public ] },
{ symbol: [ "key_t", private, "<sys/types.h>", public ] },
{ symbol: [ "key_t", private, "<sys/ipc.h>", public ] },
+ { symbol: [ "lconv", private, "<locale.h>", public ] },
+ { symbol: [ "ldiv_t", private, "<stdlib.h>", public ] },
+ { symbol: [ "lldiv_t", private, "<stdlib.h>", public ] },
{ symbol: [ "max_align_t", private, "<stddef.h>", public ] },
{ symbol: [ "mode_t", private, "<sys/types.h>", public ] },
- { symbol: [ "mode_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "mode_t", private, "<fcntl.h>", public ] },
+ { symbol: [ "mode_t", private, "<ndbm.h>", public ] },
+ { symbol: [ "mode_t", private, "<spawn.h>", public ] },
{ symbol: [ "mode_t", private, "<sys/ipc.h>", public ] },
{ symbol: [ "mode_t", private, "<sys/mman.h>", public ] },
+ { symbol: [ "mode_t", private, "<sys/stat.h>", public ] },
{ symbol: [ "nlink_t", private, "<sys/types.h>", public ] },
{ symbol: [ "nlink_t", private, "<sys/stat.h>", public ] },
{ symbol: [ "off64_t", private, "<sys/types.h>", public ] },
{ symbol: [ "off64_t", private, "<unistd.h>", public ] },
{ symbol: [ "off_t", private, "<sys/types.h>", public ] },
- { symbol: [ "off_t", private, "<unistd.h>", public ] },
- { symbol: [ "off_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "off_t", private, "<aio.h>", public ] },
+ { symbol: [ "off_t", private, "<fcntl.h>", public ] },
+ { symbol: [ "off_t", private, "<stdio.h>", public ] },
{ symbol: [ "off_t", private, "<sys/mman.h>", public ] },
+ { symbol: [ "off_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "off_t", private, "<unistd.h>", public ] },
{ symbol: [ "pid_t", private, "<sys/types.h>", public ] },
- { symbol: [ "pid_t", private, "<unistd.h>", public ] },
+ { symbol: [ "pid_t", private, "<fcntl.h>", public ] },
+ { symbol: [ "pid_t", private, "<sched.h>", public ] },
{ symbol: [ "pid_t", private, "<signal.h>", public ] },
+ { symbol: [ "pid_t", private, "<spawn.h>", public ] },
{ symbol: [ "pid_t", private, "<sys/msg.h>", public ] },
+ { symbol: [ "pid_t", private, "<sys/sem.h>", public ] },
{ symbol: [ "pid_t", private, "<sys/shm.h>", public ] },
+ { symbol: [ "pid_t", private, "<sys/wait.h>", public ] },
{ symbol: [ "pid_t", private, "<termios.h>", public ] },
{ symbol: [ "pid_t", private, "<time.h>", public ] },
+ { symbol: [ "pid_t", private, "<unistd.h>", public ] },
{ symbol: [ "pid_t", private, "<utmpx.h>", public ] },
{ symbol: [ "ptrdiff_t", private, "<stddef.h>", public ] },
+ { symbol: [ "regex_t", private, "<regex.h>", public ] },
+ { symbol: [ "regmatch_t", private, "<regex.h>", public ] },
+ { symbol: [ "regoff_t", private, "<regex.h>", public ] },
+ { symbol: [ "sigevent", private, "<signal.h>", public ] },
+ { symbol: [ "sigevent", private, "<aio.h>", public ] },
+ { symbol: [ "sigevent", private, "<mqueue.h>", public ] },
+ { symbol: [ "sigevent", private, "<time.h>", public ] },
+ { symbol: [ "siginfo_t", private, "<signal.h>", public ] },
+ { symbol: [ "siginfo_t", private, "<sys/wait.h>", public ] },
{ symbol: [ "sigset_t", private, "<signal.h>", public ] },
- { symbol: [ "sigset_t", private, "<sys/epoll.h>", public ] },
+ { symbol: [ "sigset_t", private, "<spawn.h>", public ] },
{ symbol: [ "sigset_t", private, "<sys/select.h>", public ] },
- { symbol: [ "socklen_t", private, "<bits/socket.h>", private ] },
- { symbol: [ "socklen_t", private, "<unistd.h>", public ] },
- { symbol: [ "socklen_t", private, "<arpa/inet.h>", public ] },
+ { symbol: [ "sigval", private, "<signal.h>", public ] },
+ { symbol: [ "sockaddr", private, "<sys/socket.h>", public ] },
+ { symbol: [ "socklen_t", private, "<sys/socket.h>", public ] },
+ { symbol: [ "socklen_t", private, "<netdb.h>", public ] },
{ symbol: [ "ssize_t", private, "<sys/types.h>", public ] },
- { symbol: [ "ssize_t", private, "<unistd.h>", public ] },
+ { symbol: [ "ssize_t", private, "<aio.h>", public ] },
{ symbol: [ "ssize_t", private, "<monetary.h>", public ] },
+ { symbol: [ "ssize_t", private, "<mqueue.h>", public ] },
+ { symbol: [ "ssize_t", private, "<stdio.h>", public ] },
{ symbol: [ "ssize_t", private, "<sys/msg.h>", public ] },
+ { symbol: [ "ssize_t", private, "<sys/socket.h>", public ] },
+ { symbol: [ "ssize_t", private, "<sys/uio.h>", public ] },
+ { symbol: [ "ssize_t", private, "<unistd.h>", public ] },
{ symbol: [ "suseconds_t", private, "<sys/types.h>", public ] },
- { symbol: [ "suseconds_t", private, "<sys/time.h>", public ] },
{ symbol: [ "suseconds_t", private, "<sys/select.h>", public ] },
- { symbol: [ "time_t", private, "<sys/types.h>", public ] },
+ { symbol: [ "suseconds_t", private, "<sys/time.h>", public ] },
{ symbol: [ "time_t", private, "<time.h>", public ] },
+ { symbol: [ "time_t", private, "<sched.h>", public ] },
+ { symbol: [ "time_t", private, "<sys/msg.h>", public ] },
+ { symbol: [ "time_t", private, "<sys/select.h>", public ] },
+ { symbol: [ "time_t", private, "<sys/sem.h>", public ] },
+ { symbol: [ "time_t", private, "<sys/shm.h>", public ] },
+ { symbol: [ "time_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "time_t", private, "<sys/time.h>", public ] },
+ { symbol: [ "time_t", private, "<sys/types.h>", public ] },
+ { symbol: [ "time_t", private, "<utime.h>", public ] },
+ { symbol: [ "timer_t", private, "<sys/types.h>", public ] },
+ { symbol: [ "timer_t", private, "<time.h>", public ] },
{ symbol: [ "timespec", private, "<time.h>", public ] },
+ { symbol: [ "timespec", private, "<aio.h>", public ] },
+ { symbol: [ "timespec", private, "<mqueue.h>", public ] },
+ { symbol: [ "timespec", private, "<sched.h>", public ] },
+ { symbol: [ "timespec", private, "<signal.h>", public ] },
+ { symbol: [ "timespec", private, "<sys/select.h>", public ] },
+ { symbol: [ "timespec", private, "<sys/stat.h>", public ] },
{ symbol: [ "timeval", private, "<sys/time.h>", public ] },
+ { symbol: [ "timeval", private, "<sys/resource.h>", public ] },
+ { symbol: [ "timeval", private, "<sys/select.h>", public ] },
+ { symbol: [ "timeval", private, "<utmpx.h>", public ] },
{ symbol: [ "u_char", private, "<sys/types.h>", public ] },
{ symbol: [ "u_char", private, "<rpc/types.h>", public ] },
{ symbol: [ "uid_t", private, "<sys/types.h>", public ] },
- { symbol: [ "uid_t", private, "<unistd.h>", public ] },
{ symbol: [ "uid_t", private, "<pwd.h>", public ] },
{ symbol: [ "uid_t", private, "<signal.h>", public ] },
{ symbol: [ "uid_t", private, "<stropts.h>", public ] },
{ symbol: [ "uid_t", private, "<sys/ipc.h>", public ] },
{ symbol: [ "uid_t", private, "<sys/stat.h>", public ] },
+ { symbol: [ "uid_t", private, "<unistd.h>", public ] },
{ symbol: [ "useconds_t", private, "<sys/types.h>", public ] },
{ symbol: [ "useconds_t", private, "<unistd.h>", public ] },
{ symbol: [ "wchar_t", private, "<stddef.h>", public ] },
{ symbol: [ "wchar_t", private, "<stdlib.h>", public ] },
- # glob.h seems to define size_t if necessary, but it should come from stddef.
{ symbol: [ "size_t", private, "<stddef.h>", public ] },
+ { symbol: [ "size_t", private, "<aio.h>", public ] },
+ { symbol: [ "size_t", private, "<glob.h>", public ] },
+ { symbol: [ "size_t", private, "<grp.h>", public ] },
+ { symbol: [ "size_t", private, "<iconv.h>", public ] },
+ { symbol: [ "size_t", private, "<monetary.h>", public ] },
+ { symbol: [ "size_t", private, "<mqueue.h>", public ] },
+ { symbol: [ "size_t", private, "<ndbm.h>", public ] },
+ { symbol: [ "size_t", private, "<pwd.h>", public ] },
+ { symbol: [ "size_t", private, "<regex.h>", public ] },
+ { symbol: [ "size_t", private, "<search.h>", public ] },
+ { symbol: [ "size_t", private, "<signal.h>", public ] },
{ symbol: [ "size_t", private, "<stdio.h>", public ] },
{ symbol: [ "size_t", private, "<stdlib.h>", public ] },
{ symbol: [ "size_t", private, "<string.h>", public ] },
+ { symbol: [ "size_t", private, "<strings.h>", public ] },
+ { symbol: [ "size_t", private, "<sys/mman.h>", public ] },
+ { symbol: [ "size_t", private, "<sys/msg.h>", public ] },
+ { symbol: [ "size_t", private, "<sys/sem.h>", public ] },
+ { symbol: [ "size_t", private, "<sys/shm.h>", public ] },
+ { symbol: [ "size_t", private, "<sys/socket.h>", public ] },
+ { symbol: [ "size_t", private, "<sys/types.h>", public ] },
+ { symbol: [ "size_t", private, "<sys/uio.h>", public ] },
{ symbol: [ "size_t", private, "<time.h>", public ] },
{ symbol: [ "size_t", private, "<uchar.h>", public ] },
+ { symbol: [ "size_t", private, "<unistd.h>", public ] },
{ symbol: [ "size_t", private, "<wchar.h>", public ] },
+ { symbol: [ "size_t", private, "<wordexp.h>", public ] },
# 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
@@ -125,6 +221,8 @@
{ symbol: [ "EOF", private, "<libio.h>", public ] },
{ symbol: [ "FILE", private, "<stdio.h>", public ] },
{ symbol: [ "va_list", private, "<stdarg.h>", public ] },
+ { symbol: [ "va_list", private, "<stdio.h>", public ] },
+ { symbol: [ "va_list", private, "<wchar.h>", public ] },
# These are symbols that could be defined in either stdlib.h or
# malloc.h, but we always want the stdlib location.
{ symbol: [ "malloc", private, "<stdlib.h>", public ] },
diff --git a/iwyu.cc b/iwyu.cc
index 355e793..61350ca 100644
--- a/iwyu.cc
+++ b/iwyu.cc
@@ -167,6 +167,7 @@ using clang::ConstructorUsingShadowDecl;
using clang::Decl;
using clang::DeclContext;
using clang::DeclRefExpr;
+using clang::DeducedTemplateSpecializationType;
using clang::EnumType;
using clang::Expr;
using clang::FileEntry;
@@ -191,6 +192,7 @@ using clang::QualifiedTypeLoc;
using clang::RecordDecl;
using clang::RecursiveASTVisitor;
using clang::ReferenceType;
+using clang::Sema;
using clang::SourceLocation;
using clang::Stmt;
using clang::SubstTemplateTypeParmType;
@@ -532,17 +534,10 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> {
//------------------------------------------------------------
// (4) Add implicit text.
-
- // When we see an object that has implicit text that iwyu
- // wants to look at, we make callbacks as if that text had
- // been explicitly written. Here's text we consider:
//
- // * CXXDestructorDecl: a destructor call for each non-POD field
- // in the dtor's class, and each base type of that class.
- // * CXXRecordDecl: a CXXConstructorDecl for each implicit
- // constructor (zero-arg and copy). A CXXDestructor decl
- // if the destructor is implicit. A CXXOperatorCallDecl if
- // operator= is explicit.
+ // This simulates a call to the destructor of every non-POD field and base
+ // class in all classes with destructors, to mark them as used by virtue of
+ // being class members.
bool TraverseCXXDestructorDecl(clang::CXXDestructorDecl* decl) {
if (!Base::TraverseCXXDestructorDecl(decl)) return false;
if (CanIgnoreCurrentASTNode()) return true;
@@ -575,69 +570,12 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> {
return true;
}
- // clang lazily constructs the implicit methods of a C++ class (the
- // default constructor and destructor, etc) -- it only bothers to
- // create a CXXMethodDecl if someone actually calls these classes.
- // But we need to be non-lazy: iwyu depends on analyzing what future
- // code *may* call in a class, not what current code *does*. So we
- // force all the lazy evaluation to happen here. This will
- // (possibly) add a bunch of MethodDecls to the AST, as children of
- // decl. We're hoping it will always be safe to modify the AST
- // while it's being traversed!
- void InstantiateImplicitMethods(CXXRecordDecl* decl) {
- if (decl->isDependentType()) // only instantiate if class is instantiated
- return;
-
- clang::Sema& sema = compiler()->getSema();
- DeclContext::lookup_result ctors = sema.LookupConstructors(decl);
- for (NamedDecl* ctor_lookup : ctors) {
- // Ignore templated or inheriting constructors.
- if (isa<FunctionTemplateDecl>(ctor_lookup) ||
- isa<UsingDecl>(ctor_lookup) ||
- isa<ConstructorUsingShadowDecl>(ctor_lookup))
- continue;
- CXXConstructorDecl* ctor = cast<CXXConstructorDecl>(ctor_lookup);
- if (!ctor->hasBody() && !ctor->isDeleted() && ctor->isImplicit()) {
- if (sema.getSpecialMember(ctor) == clang::Sema::CXXDefaultConstructor) {
- sema.DefineImplicitDefaultConstructor(CurrentLoc(), ctor);
- } else {
- // TODO(nlewycky): enable this!
- //sema.DefineImplicitCopyConstructor(CurrentLoc(), ctor);
- }
- }
- // Unreferenced template constructors stay uninstantiated on purpose.
- }
-
- if (CXXDestructorDecl* dtor = sema.LookupDestructor(decl)) {
- if (!dtor->isDeleted()) {
- if (!dtor->hasBody() && dtor->isImplicit())
- sema.DefineImplicitDestructor(CurrentLoc(), dtor);
- if (!dtor->isDefined() && dtor->getTemplateInstantiationPattern())
- sema.PendingInstantiations.emplace_back(dtor, CurrentLoc());
- }
- }
-
- // TODO(nlewycky): copy assignment operator
-
- // clang queues up method instantiations. We need to process them now.
- sema.PerformPendingInstantiations();
- }
-
- // Handle implicit methods that otherwise wouldn't be seen by RAV.
- bool TraverseCXXRecordDecl(clang::CXXRecordDecl* decl) {
- if (CanIgnoreCurrentASTNode()) return true;
- // We only care about classes that are actually defined.
- if (decl && decl->isThisDeclarationADefinition()) {
- InstantiateImplicitMethods(decl);
- }
-
- return Base::TraverseCXXRecordDecl(decl);
- }
-
+ // Class template specialization are similar to regular C++ classes,
+ // particularly they need the same custom handling of implicit destructors.
bool TraverseClassTemplateSpecializationDecl(
clang::ClassTemplateSpecializationDecl* decl) {
if (!Base::TraverseClassTemplateSpecializationDecl(decl)) return false;
- return TraverseCXXRecordDecl(decl);
+ return Base::TraverseCXXRecordDecl(decl);
}
//------------------------------------------------------------
@@ -1322,7 +1260,26 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
for (const NamedDecl* redecl : GetClassRedecls(decl)) {
if (GetFileEntry(redecl) == macro_def_file && IsForwardDecl(redecl)) {
fwd_decl = redecl;
+ break;
+ }
+ }
+ if (!fwd_decl) {
+ if (const auto* func_decl = dyn_cast<FunctionDecl>(decl)) {
+ if (const FunctionTemplateDecl* ft_decl =
+ func_decl->getPrimaryTemplate()) {
+ VERRS(5) << "No fwd-decl found, looking for function template decl\n";
+ for (const NamedDecl* redecl : ft_decl->redecls()) {
+ if (GetFileEntry(redecl) == macro_def_file) {
+ fwd_decl = redecl;
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if (fwd_decl) {
// Make sure we keep that forward-declaration, even if it's probably
// unused in this file.
IwyuFileInfo* file_info =
@@ -1330,8 +1287,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
file_info->ReportForwardDeclareUse(
spelling_loc, fwd_decl,
ComputeUseFlags(current_ast_node()), nullptr);
- break;
- }
}
// Resolve the best use location based on our current knowledge.
@@ -1460,12 +1415,12 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
}
set<const Type*> GetCallerResponsibleTypesForTypedef(
- const TypedefDecl* decl) {
+ const TypedefNameDecl* decl) {
set<const Type*> retval;
const Type* underlying_type = decl->getUnderlyingType().getTypePtr();
// If the underlying type is itself a typedef, we recurse.
if (const TypedefType* underlying_typedef = DynCastFrom(underlying_type)) {
- if (const TypedefDecl* underlying_typedef_decl
+ if (const TypedefNameDecl* underlying_typedef_decl
= DynCastFrom(TypeToDeclAsWritten(underlying_typedef))) {
// TODO(csilvers): if one of the intermediate typedefs
// #includes the necessary definition of the 'final'
@@ -1610,12 +1565,12 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// anywhere. ('autocast' is similar, but is handled in
// VisitCastExpr; 'fn-return-type' is also similar and is
// handled in HandleFunctionCall.)
- if (const TypedefDecl* typedef_decl = DynCastFrom(target_decl)) {
+ if (const TypedefNameDecl* typedef_decl = DynCastFrom(target_decl)) {
// One exception: if this TypedefType is being used in another
// typedef (that is, 'typedef MyTypedef OtherTypdef'), then the
// user -- the other typedef -- is never responsible for the
// underlying type. Instead, users of that typedef are.
- if (!current_ast_node()->template ParentIsA<TypedefDecl>()) {
+ if (!current_ast_node()->template ParentIsA<TypedefNameDecl>()) {
const set<const Type*>& underlying_types
= GetCallerResponsibleTypesForTypedef(typedef_decl);
if (!underlying_types.empty()) {
@@ -1757,7 +1712,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// iwyu will demand the full type of pair, but not of its template
// arguments. This is handled not here, but below, in
// VisitSubstTemplateTypeParmType.
- bool VisitTypedefDecl(clang::TypedefDecl* decl) {
+ bool VisitTypedefNameDecl(clang::TypedefNameDecl* decl) {
if (CanIgnoreCurrentASTNode()) return true;
const Type* underlying_type = decl->getUnderlyingType().getTypePtr();
const Type* deref_type
@@ -1770,7 +1725,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
current_ast_node()->set_in_forward_declare_context(false);
}
- return Base::VisitTypedefDecl(decl);
+ return Base::VisitTypedefNameDecl(decl);
}
// If we're a declared (not defined) function, all our types --
@@ -1977,8 +1932,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
case clang::CK_BooleanToSignedIntegral:
case clang::CK_FixedPointCast:
case clang::CK_FixedPointToBoolean:
- case clang::CK_FixedPointToFloating:
- case clang::CK_FixedPointToIntegral:
case clang::CK_FloatingCast:
case clang::CK_FloatingComplexCast:
case clang::CK_FloatingComplexToBoolean:
@@ -1986,7 +1939,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
case clang::CK_FloatingComplexToReal:
case clang::CK_FloatingRealToComplex:
case clang::CK_FloatingToBoolean:
- case clang::CK_FloatingToFixedPoint:
case clang::CK_FloatingToIntegral:
case clang::CK_FunctionToPointerDecay:
case clang::CK_IntegralCast:
@@ -1996,7 +1948,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
case clang::CK_IntegralComplexToReal:
case clang::CK_IntegralRealToComplex:
case clang::CK_IntegralToBoolean:
- case clang::CK_IntegralToFixedPoint:
case clang::CK_IntegralToFloating:
case clang::CK_IntegralToPointer:
case clang::CK_MemberPointerToBoolean:
@@ -2025,7 +1976,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// Kinds for reinterpret_cast and const_cast, which need no full types.
case clang::CK_BitCast: // used for reinterpret_cast
case clang::CK_LValueBitCast: // used for reinterpret_cast
- case clang::CK_LValueToRValueBitCast: // used for reinterpret_cast
case clang::CK_NoOp: // used for const_cast, etc
break;
@@ -2428,15 +2378,15 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// contents don't matter that much.
using clang::Optional;
using clang::DirectoryLookup;
- using clang::FileEntryRef;
+ using clang::FileEntry;
const FileEntry* use_file = CurrentFileEntry();
const DirectoryLookup* curdir = nullptr;
- Optional<FileEntryRef> file = compiler()->getPreprocessor().LookupFile(
+ auto file = compiler()->getPreprocessor().LookupFile(
CurrentLoc(), "new", true, nullptr, use_file, curdir, nullptr,
- nullptr, nullptr, nullptr, nullptr, false);
+ nullptr, nullptr, nullptr, false);
if (file) {
preprocessor_info().FileInfoFor(use_file)->ReportFullSymbolUse(
- CurrentLoc(), *file, "operator new");
+ CurrentLoc(), file, "operator new");
}
}
}
@@ -2591,7 +2541,7 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> {
// If we're in a typedef, we don't want to forward-declare even if
// we're a pointer. ('typedef Foo* Bar; Bar x; x->a' needs full
// type of Foo.)
- if (ast_node->ParentIsA<TypedefDecl>())
+ if (ast_node->ParentIsA<TypedefNameDecl>())
return false;
// If we ourselves are a forward-decl -- that is, we're the type
@@ -3656,11 +3606,31 @@ class IwyuAstConsumer
const_cast<IwyuPreprocessorInfo*>(&preprocessor_info())->
HandlePreprocessingDone();
+ TranslationUnitDecl* tu_decl = context.getTranslationUnitDecl();
+
+ // Sema::TUScope is reset after parsing, but Sema::getCurScope still points
+ // to the translation unit decl scope. TUScope is required for lookup in
+ // some complex scenarios, so re-wire it before running IWYU AST passes.
+ // Assert their expected state so we notice if these assumptions change.
+ Sema& sema = compiler()->getSema();
+ CHECK_(sema.TUScope == nullptr);
+ CHECK_(sema.getCurScope() != nullptr);
+ sema.TUScope = sema.getCurScope();
+
// We run a separate pass to force parsing of late-parsed function
// templates.
- ParseFunctionTemplates(context.getTranslationUnitDecl());
+ ParseFunctionTemplates(sema, tu_decl);
- TraverseDecl(context.getTranslationUnitDecl());
+ // Clang lazily constructs the implicit methods of a C++ class (the
+ // default constructor and destructor, etc) -- it only bothers to
+ // create a CXXMethodDecl if someone actually calls these classes.
+ // But we need to be non-lazy: IWYU depends on analyzing what future
+ // code *may* call in a class, not what current code *does*. So we
+ // force all the lazy evaluation to happen here.
+ InstantiateImplicitMethods(sema, tu_decl);
+
+ // Run IWYU analysis.
+ TraverseDecl(tu_decl);
// Check if any unrecoverable errors have occurred.
// There is no point in continuing when the AST is in a bad state.
@@ -3705,9 +3675,8 @@ class IwyuAstConsumer
exit(EXIT_SUCCESS_OFFSET + num_edits);
}
- void ParseFunctionTemplates(TranslationUnitDecl* decl) {
- set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(decl);
- clang::Sema& sema = compiler()->getSema();
+ void ParseFunctionTemplates(Sema& sema, TranslationUnitDecl* tu_decl) {
+ set<FunctionDecl*> late_parsed_decls = GetLateParsedFunctionDecls(tu_decl);
// If we have any late-parsed functions, make sure the
// -fdelayed-template-parsing flag is on. Otherwise we don't know where
@@ -3730,6 +3699,55 @@ class IwyuAstConsumer
}
}
+ void InstantiateImplicitMethods(Sema& sema, TranslationUnitDecl* tu_decl) {
+ // Collect all implicit ctors/dtors that need to be instantiated.
+ struct Visitor : public RecursiveASTVisitor<Visitor> {
+ Visitor(Sema& sema) : sema(sema) {
+ }
+
+ bool VisitCXXRecordDecl(CXXRecordDecl* decl) {
+ if (CanIgnoreLocation(GetLocation(decl)))
+ return true;
+
+ if (!decl->getDefinition() || decl->isDependentContext() ||
+ decl->isBeingDefined()) {
+ return true;
+ }
+
+ if (CXXConstructorDecl* ctor = sema.LookupDefaultConstructor(decl)) {
+ may_need_definition.insert(ctor);
+ } else if (CXXDestructorDecl* dtor = sema.LookupDestructor(decl)) {
+ may_need_definition.insert(dtor);
+ }
+
+ return true;
+ }
+
+ Sema& sema;
+ std::set<CXXMethodDecl*> may_need_definition;
+ };
+
+ // Run visitor to collect implicit methods.
+ Visitor v(sema);
+ v.TraverseDecl(tu_decl);
+
+ // For each method collected, let Sema define them.
+ for (CXXMethodDecl* method : v.may_need_definition) {
+ if (!method->isDefaulted() || method->isDeleted() || method->hasBody())
+ continue;
+
+ SourceLocation loc = GetLocation(method->getParent());
+ if (auto* ctor = dyn_cast<CXXConstructorDecl>(method)) {
+ sema.DefineImplicitDefaultConstructor(loc, ctor);
+ } else if (auto* dtor = dyn_cast<CXXDestructorDecl>(method)) {
+ sema.DefineImplicitDestructor(loc, dtor);
+ }
+ }
+
+ // Clang queues up method instantiations. Process them now.
+ sema.PerformPendingInstantiations();
+ }
+
//------------------------------------------------------------
// AST visitors. We start by adding a visitor callback for
// most of the subclasses of Decl/Stmt/Type listed in:
@@ -3913,14 +3931,13 @@ class IwyuAstConsumer
// TODO(csilvers): we can probably relax this rule in .cc files.
// TODO(csilvers): this should really move into IwyuBaseASTVisitor
// (that way we'll correctly identify need for hash<> in hash_set).
- // This is a Traverse*() because Visit*() can't call HandleFunctionCall().
- bool TraverseTypedefDecl(clang::TypedefDecl* decl) {
- // Before we go up the tree, make sure the parents know we don't
- // forward-declare the underlying type of a typedef decl.
- current_ast_node()->set_in_forward_declare_context(false);
- if (!Base::TraverseTypedefDecl(decl))
- return false;
- if (CanIgnoreCurrentASTNode()) return true;
+ // This is called from Traverse*() because Visit*()
+ // can't call HandleFunctionCall().
+ bool HandleAliasedClassMethods(TypedefNameDecl* decl) {
+ if (CanIgnoreCurrentASTNode())
+ return true;
+ if (current_ast_node()->in_forward_declare_context())
+ return true;
const Type* underlying_type = decl->getUnderlyingType().getTypePtr();
const Decl* underlying_decl = TypeToDeclAsWritten(underlying_type);
@@ -3947,6 +3964,20 @@ class IwyuAstConsumer
return true;
}
+ bool TraverseTypedefDecl(clang::TypedefDecl* decl) {
+ if (!Base::TraverseTypedefDecl(decl))
+ return false;
+
+ return HandleAliasedClassMethods(decl);
+ }
+
+ bool TraverseTypeAliasDecl(clang::TypeAliasDecl* decl) {
+ if (!Base::TraverseTypeAliasDecl(decl))
+ return false;
+
+ return HandleAliasedClassMethods(decl);
+ }
+
// --- Visitors of types derived from clang::Stmt.
// Called whenever a variable, function, enum, etc is used.
@@ -4063,18 +4094,21 @@ class IwyuAstConsumer
bool VisitTemplateName(TemplateName template_name) {
if (CanIgnoreCurrentASTNode()) return true;
if (!Base::VisitTemplateName(template_name)) return false;
- // The only time we can see a TemplateName not in the
- // context of a TemplateSpecializationType is when it's
- // the default argument of a template template arg:
+ // We can see TemplateName not in the context of aTemplateSpecializationType
+ // when it's either the default argument of a template template arg:
// template<template<class T> class A = TplNameWithoutTST> class Foo ...
- // So that's the only case we need to handle here.
+ // or a deduced template specialization:
+ // std::pair x(10, 20); // type of x is really std::pair<int, int>
+ // So that's the only cases we need to handle here.
// TODO(csilvers): check if this is really forward-declarable or
// not. You *could* do something like: 'template<template<class
// T> class A = Foo> class C { A<int>* x; };' and never
// dereference x, but that's pretty unlikely. So for now, we just
// assume these default template template args always need full
// type info.
- if (IsDefaultTemplateTemplateArg(current_ast_node())) {
+ const ASTNode* ast_node = current_ast_node();
+ if (ast_node->ParentIsA<DeducedTemplateSpecializationType>() ||
+ IsDefaultTemplateTemplateArg(ast_node)) {
current_ast_node()->set_in_forward_declare_context(false);
ReportDeclUse(CurrentLoc(), template_name.getAsTemplateDecl());
}
@@ -4140,7 +4174,6 @@ class IwyuAction : public ASTFrontendAction {
#include "iwyu_driver.h"
#include "clang/Frontend/FrontendAction.h"
-#include "llvm/Support/ManagedStatic.h"
#include "llvm/Support/TargetSelect.h"
using include_what_you_use::OptionsParser;
@@ -4148,12 +4181,11 @@ using include_what_you_use::IwyuAction;
using include_what_you_use::CreateCompilerInstance;
int main(int argc, char **argv) {
- // Must initialize X86 target to be able to parse Microsoft inline
- // assembly. We do this unconditionally, because it allows an IWYU
- // built for non-X86 targets to parse MS inline asm without choking.
- LLVMInitializeX86TargetInfo();
- LLVMInitializeX86TargetMC();
- LLVMInitializeX86AsmParser();
+ // X86 target is required to parse Microsoft inline assembly, so we hope it's
+ // part of all targets. Clang parser will complain otherwise.
+ llvm::InitializeAllTargetInfos();
+ llvm::InitializeAllTargetMCs();
+ llvm::InitializeAllAsmParsers();
// The command line should look like
// path/to/iwyu -Xiwyu --verbose=4 [-Xiwyu --other_iwyu_flag]... CLANG_FLAGS... foo.cc
diff --git a/iwyu_ast_util.cc b/iwyu_ast_util.cc
index 9982145..50477eb 100644
--- a/iwyu_ast_util.cc
+++ b/iwyu_ast_util.cc
@@ -25,7 +25,6 @@
#include "llvm/Support/Casting.h"
#include "llvm/Support/raw_ostream.h"
#include "clang/AST/ASTContext.h"
-#include "clang/AST/ASTDumper.h"
#include "clang/AST/CanonicalType.h"
#include "clang/AST/Decl.h"
#include "clang/AST/DeclBase.h"
@@ -47,7 +46,6 @@ namespace clang {
class FileEntry;
} // namespace clang
-using clang::ASTDumper;
using clang::BlockPointerType;
using clang::CXXConstructExpr;
using clang::CXXConstructorDecl;
@@ -446,14 +444,12 @@ string PrintableDecl(const Decl* decl, bool terse/*=true*/) {
string PrintableStmt(const Stmt* stmt) {
std::string buffer;
raw_string_ostream ostream(buffer);
- ASTDumper dumper(ostream, /*ShowColors=*/false);
- dumper.Visit(stmt);
+ stmt->dump(ostream, *GlobalSourceManager());
return ostream.str();
}
void PrintStmt(const Stmt* stmt) {
- ASTDumper dumper(llvm::errs(), /*ShowColors=*/false);
- dumper.Visit(stmt);
+ stmt->dump(*GlobalSourceManager()); // This prints to errs().
}
string PrintableType(const Type* type) {
@@ -1095,11 +1091,14 @@ bool DeclsAreInSameClass(const Decl* decl1, const Decl* decl2) {
return decl1->getDeclContext()->isRecord();
}
-bool IsBuiltinFunction(const clang::NamedDecl* decl,
- const std::string& symbol_name) {
+bool IsBuiltinFunction(const clang::NamedDecl* decl) {
if (const clang::IdentifierInfo* iden = decl->getIdentifier()) {
- return iden->getBuiltinID() != 0 &&
- !clang::Builtin::Context::isBuiltinFunc(symbol_name.c_str());
+ unsigned builtin_id = iden->getBuiltinID();
+ if (builtin_id != 0) {
+ const clang::Builtin::Context& ctx = decl->getASTContext().BuiltinInfo;
+ return !ctx.isPredefinedLibFunction(builtin_id) &&
+ !ctx.isHeaderDependentFunction(builtin_id);
+ }
}
return false;
}
diff --git a/iwyu_ast_util.h b/iwyu_ast_util.h
index 18ddf2d..28668f7 100644
--- a/iwyu_ast_util.h
+++ b/iwyu_ast_util.h
@@ -652,8 +652,7 @@ const clang::NamedDecl* GetNonfriendClassRedecl(const clang::NamedDecl* decl);
bool DeclsAreInSameClass(const clang::Decl* decl1, const clang::Decl* decl2);
// Returns true if the given decl/name is a builtin function
-bool IsBuiltinFunction(const clang::NamedDecl* decl,
- const std::string& symbol_name);
+bool IsBuiltinFunction(const clang::NamedDecl* decl);
// --- Utilities for Type.
diff --git a/iwyu_driver.cc b/iwyu_driver.cc
index 42fea35..d9b96b7 100644
--- a/iwyu_driver.cc
+++ b/iwyu_driver.cc
@@ -205,8 +205,11 @@ CompilerInstance* CreateCompilerInstance(int argc, const char **argv) {
// Initialize a compiler invocation object from the clang (-cc1) arguments.
const ArgStringList &cc_arguments = command.getArguments();
+ const char** args_start = const_cast<const char**>(cc_arguments.data());
+ const char** args_end = args_start + cc_arguments.size();
std::shared_ptr<CompilerInvocation> invocation(new CompilerInvocation);
- CompilerInvocation::CreateFromArgs(*invocation, cc_arguments, diagnostics);
+ CompilerInvocation::CreateFromArgs(*invocation,
+ args_start, args_end, diagnostics);
invocation->getFrontendOpts().DisableFree = false;
// Use libc++ headers bundled with Xcode.app on macOS.
diff --git a/iwyu_globals.cc b/iwyu_globals.cc
index 36ac3ae..96b728c 100644
--- a/iwyu_globals.cc
+++ b/iwyu_globals.cc
@@ -91,6 +91,8 @@ static void PrintHelp(const char* extra_msg) {
" the maximum line length can still be exceeded with long\n"
" file names (default: 80).\n"
" --no_comments: do not add 'why' comments.\n"
+ " --update_comments: always add 'why' comments, even if no\n"
+ " #include lines need to be added or removed.\n"
" --no_fwd_decls: do not use forward declarations.\n"
" --verbose=<level>: the higher the level, the more output.\n"
" --quoted_includes_first: when sorting includes, place quoted\n"
@@ -163,6 +165,7 @@ CommandlineFlags::CommandlineFlags()
prefix_header_include_policy(CommandlineFlags::kAdd),
pch_in_code(false),
no_comments(false),
+ update_comments(false),
no_fwd_decls(false),
quoted_includes_first(false),
cxx17ns(false) {
@@ -182,6 +185,7 @@ int CommandlineFlags::ParseArgv(int argc, char** argv) {
{"pch_in_code", no_argument, nullptr, 'h'},
{"max_line_length", required_argument, nullptr, 'l'},
{"no_comments", no_argument, nullptr, 'o'},
+ {"update_comments", no_argument, nullptr, 'u'},
{"no_fwd_decls", no_argument, nullptr, 'f'},
{"quoted_includes_first", no_argument, nullptr, 'q' },
{"cxx17ns", no_argument, nullptr, 'C'},
@@ -197,6 +201,7 @@ int CommandlineFlags::ParseArgv(int argc, char** argv) {
case 'm': mapping_files.push_back(optarg); break;
case 'n': no_default_mappings = true; break;
case 'o': no_comments = true; break;
+ case 'u': update_comments = true; break;
case 'f': no_fwd_decls = true; break;
case 'x':
if (strcmp(optarg, "add") == 0) {
diff --git a/iwyu_globals.h b/iwyu_globals.h
index 242cdf6..eefb8ce 100644
--- a/iwyu_globals.h
+++ b/iwyu_globals.h
@@ -98,6 +98,7 @@ struct CommandlineFlags {
PrefixHeaderIncludePolicy prefix_header_include_policy;
bool pch_in_code; // Treat the first seen include as a PCH. No short option.
bool no_comments; // Disable 'why' comments. No short option.
+ bool update_comments; // Force 'why' comments. No short option.
bool no_fwd_decls; // Disable forward declarations.
bool quoted_includes_first; // Place quoted includes first in sort order.
bool cxx17ns; // -C: C++17 nested namespace syntax
diff --git a/iwyu_include_picker.cc b/iwyu_include_picker.cc
index f5d2dbc..77928fa 100644
--- a/iwyu_include_picker.cc
+++ b/iwyu_include_picker.cc
@@ -16,6 +16,7 @@
// not hash_map: it's not as portable and needs hash<string>.
#include <map> // for map, map<>::mapped_type, etc
#include <memory>
+#include <regex>
#include <string> // for string, basic_string, etc
#include <system_error> // for error_code
#include <utility> // for pair, make_pair
@@ -33,7 +34,6 @@
#include "llvm/Support/ErrorOr.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/MemoryBuffer.h"
-#include "llvm/Support/Regex.h"
#include "llvm/Support/SourceMgr.h"
#include "llvm/Support/YAMLParser.h"
#include "clang/Basic/FileManager.h"
@@ -89,19 +89,33 @@ const IncludeMapEntry libc_symbol_map[] = {
// 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.
- { "blksize_t", kPrivate, "<sys/types.h>", kPublic },
- { "blkcnt_t", kPrivate, "<sys/stat.h>", kPublic },
+ { "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 },
@@ -109,93 +123,175 @@ const IncludeMapEntry libc_symbol_map[] = {
{ "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 },
{ "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 },
+ { "intmax_t", kPrivate, "<inttypes.h>", kPublic },
+ { "uintmax_t", kPrivate, "<stdint.h>", kPublic },
+ { "uintmax_t", kPrivate, "<inttypes.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, "<sys/types.h>", kPublic },
{ "int8_t", kPrivate, "<stdint.h>", kPublic },
+ { "int8_t", kPrivate, "<inttypes.h>", kPublic },
{ "int16_t", kPrivate, "<stdint.h>", kPublic },
+ { "int16_t", kPrivate, "<inttypes.h>", kPublic },
{ "int32_t", kPrivate, "<stdint.h>", kPublic },
+ { "int32_t", kPrivate, "<inttypes.h>", kPublic },
{ "int64_t", kPrivate, "<stdint.h>", kPublic },
+ { "int64_t", kPrivate, "<inttypes.h>", kPublic },
{ "uint8_t", kPrivate, "<stdint.h>", kPublic },
+ { "uint8_t", kPrivate, "<inttypes.h>", kPublic },
{ "uint16_t", kPrivate, "<stdint.h>", kPublic },
+ { "uint16_t", kPrivate, "<inttypes.h>", kPublic },
{ "uint32_t", kPrivate, "<stdint.h>", kPublic },
+ { "uint32_t", kPrivate, "<inttypes.h>", kPublic },
{ "uint64_t", kPrivate, "<stdint.h>", kPublic },
+ { "uint64_t", kPrivate, "<inttypes.h>", kPublic },
{ "intptr_t", kPrivate, "<stdint.h>", kPublic },
+ { "intptr_t", kPrivate, "<inttypes.h>", kPublic },
{ "uintptr_t", kPrivate, "<stdint.h>", kPublic },
- { "intptr_t", kPrivate, "<unistd.h>", kPublic },
+ { "uintptr_t", kPrivate, "<inttypes.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, "<sys/stat.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 },
{ "off64_t", kPrivate, "<sys/types.h>", kPublic },
{ "off64_t", kPrivate, "<unistd.h>", kPublic },
{ "off_t", kPrivate, "<sys/types.h>", kPublic },
- { "off_t", kPrivate, "<unistd.h>", kPublic },
- { "off_t", kPrivate, "<sys/stat.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 },
{ "pid_t", kPrivate, "<sys/types.h>", kPublic },
- { "pid_t", kPrivate, "<unistd.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, "<sys/epoll.h>", kPublic },
+ { "sigset_t", kPrivate, "<spawn.h>", kPublic },
{ "sigset_t", kPrivate, "<sys/select.h>", kPublic },
- { "socklen_t", kPrivate, "<bits/socket.h>", kPrivate },
- { "socklen_t", kPrivate, "<unistd.h>", kPublic },
- { "socklen_t", kPrivate, "<arpa/inet.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, "<unistd.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 },
{ "suseconds_t", kPrivate, "<sys/types.h>", kPublic },
- { "suseconds_t", kPrivate, "<sys/time.h>", kPublic },
{ "suseconds_t", kPrivate, "<sys/select.h>", kPublic },
- { "time_t", kPrivate, "<sys/types.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 },
{ "u_char", kPrivate, "<sys/types.h>", kPublic },
{ "u_char", kPrivate, "<rpc/types.h>", kPublic },
{ "uid_t", kPrivate, "<sys/types.h>", kPublic },
- { "uid_t", kPrivate, "<unistd.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 },
- // glob.h seems to define size_t if necessary, but it should come from stddef.
// 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
@@ -204,6 +300,8 @@ const IncludeMapEntry libc_symbol_map[] = {
{ "EOF", kPrivate, "<libio.h>", kPublic },
{ "FILE", kPrivate, "<stdio.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 },
@@ -1315,16 +1413,17 @@ void IncludePicker::ExpandRegexes() {
for (const string& regex_key : filepath_include_map_regex_keys) {
const vector<MappedInclude>& map_to = filepath_include_map_[regex_key];
// Enclose the regex in ^(...)$ for full match.
- llvm::Regex regex(std::string("^(" + regex_key.substr(1) + ")$"));
- if (regex.match(hdr, nullptr) && !ContainsQuotedInclude(map_to, hdr)) {
+ std::regex regex(std::string("^(" + regex_key.substr(1) + ")$"));
+ if (std::regex_match(hdr, regex) &&
+ !ContainsQuotedInclude(map_to, hdr)) {
Extend(&filepath_include_map_[hdr], filepath_include_map_[regex_key]);
MarkVisibility(&include_visibility_map_, hdr,
include_visibility_map_[regex_key]);
}
}
for (const string& regex_key : friend_to_headers_map_regex_keys) {
- llvm::Regex regex(std::string("^(" + regex_key.substr(1) + ")$"));
- if (regex.match(hdr, nullptr)) {
+ std::regex regex(std::string("^(" + regex_key.substr(1) + ")$"));
+ if (std::regex_match(hdr, regex)) {
InsertAllInto(friend_to_headers_map_[regex_key],
&friend_to_headers_map_[hdr]);
}
diff --git a/iwyu_output.cc b/iwyu_output.cc
index e6bb851..d805242 100644
--- a/iwyu_output.cc
+++ b/iwyu_output.cc
@@ -1161,7 +1161,7 @@ void ProcessFullUse(OneUse* use,
// We normally ignore uses for builtins, but when there is a mapping defined
// for the symbol, we should respect that. So, we need to determine whether
// the symbol has any mappings.
- bool is_builtin_function = IsBuiltinFunction(use->decl(), use->symbol_name());
+ bool is_builtin_function = IsBuiltinFunction(use->decl());
bool is_builtin_function_with_mappings =
is_builtin_function && HasMapping(use->symbol_name());
@@ -1987,7 +1987,7 @@ size_t PrintableDiffs(const string& filename,
break;
}
}
- if (no_adds_or_deletes) {
+ if (no_adds_or_deletes && !GlobalFlags().update_comments) {
output = "\n(" + filename + " has correct #includes/fwd-decls)\n";
return 0;
}
diff --git a/iwyu_port.h b/iwyu_port.h
index d890575..e1fabb3 100644
--- a/iwyu_port.h
+++ b/iwyu_port.h
@@ -26,7 +26,7 @@ class FatalMessageEmitter {
FatalMessageEmitter(const char* file, int line, const char* message) {
stream() << file << ":" << line << ": Assertion failed: " << message;
}
- LLVM_ATTRIBUTE_NORETURN ~FatalMessageEmitter() {
+ [[noreturn]] ~FatalMessageEmitter() {
stream() << "\n";
::abort();
#ifdef LLVM_BUILTIN_UNREACHABLE
diff --git a/iwyu_preprocessor.cc b/iwyu_preprocessor.cc
index 6dc70bf..dc72b2b 100644
--- a/iwyu_preprocessor.cc
+++ b/iwyu_preprocessor.cc
@@ -34,7 +34,6 @@
#include "clang/Lex/MacroInfo.h"
using clang::FileEntry;
-using clang::FileEntryRef;
using clang::FileID;
using clang::MacroDefinition;
using clang::MacroDirective;
@@ -704,7 +703,7 @@ void IwyuPreprocessorInfo::FileChanged(SourceLocation loc,
// Called when we see an #include, but decide we don't need to
// actually read it because it's already been #included (and is
// protected by a header guard).
-void IwyuPreprocessorInfo::FileSkipped(const FileEntryRef& file,
+void IwyuPreprocessorInfo::FileSkipped(const FileEntry& file,
const Token &filename,
SrcMgr::CharacteristicKind file_type) {
CHECK_(include_filename_loc_.isValid() &&
@@ -715,11 +714,11 @@ void IwyuPreprocessorInfo::FileSkipped(const FileEntryRef& file,
GetInstantiationLoc(filename.getLocation());
ERRSYM(GetFileEntry(include_loc))
<< "[ (#include) ] " << include_name_as_written
- << " (" << GetFilePath(&file.getFileEntry()) << ")\n";
+ << " (" << GetFilePath(&file) << ")\n";
- AddDirectInclude(include_loc, &file.getFileEntry(), include_name_as_written);
- if (ShouldReportIWYUViolationsFor(&file.getFileEntry())) {
- files_to_report_iwyu_violations_for_.insert(&file.getFileEntry());
+ AddDirectInclude(include_loc, &file, include_name_as_written);
+ if (ShouldReportIWYUViolationsFor(&file)) {
+ files_to_report_iwyu_violations_for_.insert(&file);
}
}
diff --git a/iwyu_preprocessor.h b/iwyu_preprocessor.h
index c46dbc9..00073ce 100644
--- a/iwyu_preprocessor.h
+++ b/iwyu_preprocessor.h
@@ -203,7 +203,7 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks,
void FileChanged(clang::SourceLocation loc, FileChangeReason reason,
clang::SrcMgr::CharacteristicKind file_type,
clang::FileID exiting_from_id) override;
- void FileSkipped(const clang::FileEntryRef& file, const clang::Token &filename,
+ void FileSkipped(const clang::FileEntry& file, const clang::Token &filename,
clang::SrcMgr::CharacteristicKind file_type) override;
// FileChanged is actually a multi-plexer for 4 different callbacks.
void FileChanged_EnterFile(clang::SourceLocation file_beginning);
diff --git a/iwyu_tool.py b/iwyu_tool.py
index eaf0abc..45b2a4a 100755
--- a/iwyu_tool.py
+++ b/iwyu_tool.py
@@ -42,6 +42,7 @@ import subprocess
CORRECT_RE = re.compile(r'^\((.*?) has correct #includes/fwd-decls\)$')
SHOULD_ADD_RE = re.compile(r'^(.*?) should add these lines:$')
+ADD_RE = re.compile('^(.*?) +// (.*)$')
SHOULD_REMOVE_RE = re.compile(r'^(.*?) should remove these lines:$')
FULL_LIST_RE = re.compile(r'The full include-list for (.*?):$')
END_RE = re.compile(r'^---$')
@@ -80,14 +81,17 @@ def clang_formatter(output):
elif state[0] == GENERAL:
formatted.append(line)
elif state[0] == ADD:
- formatted.append('%s:1:1: error: add the following line' % state[1])
- formatted.append(line)
+ match = ADD_RE.match(line)
+ if match:
+ formatted.append("%s:1:1: error: add '%s' (%s)" %
+ (state[1], match.group(1), match.group(2)))
+ else:
+ formatted.append("%s:1:1: error: add '%s'" % (state[1], line))
elif state[0] == REMOVE:
match = LINES_RE.match(line)
line_no = match.group(2) if match else '1'
- formatted.append('%s:%s:1: error: remove the following line' %
- (state[1], line_no))
- formatted.append(match.group(1))
+ formatted.append("%s:%s:1: error: superfluous '%s'" %
+ (state[1], line_no, match.group(1)))
return os.linesep.join(formatted)
diff --git a/iwyu_version.h b/iwyu_version.h
index 12a451f..7c3b41c 100644
--- a/iwyu_version.h
+++ b/iwyu_version.h
@@ -10,6 +10,6 @@
#ifndef INCLUDE_WHAT_YOU_USE_IWYU_VERSION_H_
#define INCLUDE_WHAT_YOU_USE_IWYU_VERSION_H_
-#define IWYU_VERSION_STRING "0.16"
+#define IWYU_VERSION_STRING "0.17"
#endif // INCLUDE_WHAT_YOU_USE_IWYU_VERSION_H_
diff --git a/tests/c/libbuiltins-direct.h b/tests/c/libbuiltins-direct.h
new file mode 100644
index 0000000..eef6b58
--- /dev/null
+++ b/tests/c/libbuiltins-direct.h
@@ -0,0 +1,10 @@
+//===--- libbuiltins-direct.h - test input file for iwyu ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <math.h>
diff --git a/tests/c/libbuiltins.c b/tests/c/libbuiltins.c
new file mode 100644
index 0000000..4ba3033
--- /dev/null
+++ b/tests/c/libbuiltins.c
@@ -0,0 +1,34 @@
+//===--- libbuiltins.c - test input file for iwyu -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Library builtins are, like normal builtins, compiled down to an intrinsic,
+// but a header still needs to be included for the program to be valid. The math
+// library (pow, round, etc) is a typical example.
+
+// IWYU_ARGS: -I .
+
+#include "tests/c/libbuiltins-direct.h"
+
+float kapow(float x) {
+ // IWYU: pow is...*math.h
+ return pow(x, 2.0F);
+}
+
+/**** IWYU_SUMMARY
+
+tests/c/libbuiltins.c should add these lines:
+#include <math.h>
+
+tests/c/libbuiltins.c should remove these lines:
+- #include "tests/c/libbuiltins-direct.h" // lines XX-XX
+
+The full include-list for tests/c/libbuiltins.c:
+#include <math.h> // for pow
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/badinc.cc b/tests/cxx/badinc.cc
index e58a98f..3c3c3aa 100644
--- a/tests/cxx/badinc.cc
+++ b/tests/cxx/badinc.cc
@@ -1094,8 +1094,10 @@ int main() {
// IWYU: I1_PtrDereferenceClass needs a declaration
I1_PtrDereferenceClass* local_i1_ptrdereference_class = 0;
int x;
- // IWYU: va_list is...*<stdarg.h>
- va_list vl; // in gcc, va_list is an internal type, so this tests <built-in>
+ // va_list is normally in <stdarg.h>, but we already have <stdio.h>
+ // available, so mappings will source it from there.
+ // IWYU: va_list is...*<stdio.h>
+ va_list vl;
D1_I1_Typedef d1_i1_typedef;
// IWYU: i1_int is...*badinc-i1.h
int vararray[i1_int];
@@ -1859,7 +1861,6 @@ int main() {
tests/cxx/badinc.cc should add these lines:
#include <ctype.h>
-#include <stdarg.h>
#include <stddef.h>
#include <list>
#include "tests/cxx/badinc-i1.h"
@@ -1889,7 +1890,6 @@ The full include-list for tests/cxx/badinc.cc:
#include "tests/cxx/badinc-inl.h"
#include <ctype.h> // for isascii
#include <setjmp.h>
-#include <stdarg.h> // for va_list
#include <stddef.h> // for offsetof
#include <algorithm> // for find
#include <fstream> // for fstream
diff --git a/tests/cxx/ctad-d1.h b/tests/cxx/ctad-d1.h
new file mode 100644
index 0000000..c492fde
--- /dev/null
+++ b/tests/cxx/ctad-d1.h
@@ -0,0 +1,10 @@
+//===--- ctad-d1.h - test input file for iwyu -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tests/cxx/ctad-i1.h"
diff --git a/tests/cxx/ctad-i1.h b/tests/cxx/ctad-i1.h
new file mode 100644
index 0000000..defd3f0
--- /dev/null
+++ b/tests/cxx/ctad-i1.h
@@ -0,0 +1,20 @@
+//===--- ctad-i1.h - test input file for iwyu -----------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+template <class Func>
+struct Deduced {
+ Deduced(Func&& deferred) : deferred(deferred) {
+ }
+
+ ~Deduced() {
+ deferred();
+ }
+
+ Func deferred;
+};
diff --git a/tests/cxx/ctad.cc b/tests/cxx/ctad.cc
new file mode 100644
index 0000000..792343b
--- /dev/null
+++ b/tests/cxx/ctad.cc
@@ -0,0 +1,33 @@
+//===--- ctad.cc - test input file for iwyu -------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// IWYU_ARGS: -I . -std=c++17
+
+// Test that C++17 CTAD (Class Template Argument Deduction) is recognized as
+// pointing back to a template, even if it's not explicitly specialized.
+
+#include "tests/cxx/ctad-d1.h"
+
+void f() {
+ // IWYU: Deduced is...*ctad-i1.h
+ Deduced d([] {});
+}
+
+/**** IWYU_SUMMARY
+
+tests/cxx/ctad.cc should add these lines:
+#include "tests/cxx/ctad-i1.h"
+
+tests/cxx/ctad.cc should remove these lines:
+- #include "tests/cxx/ctad-d1.h" // lines XX-XX
+
+The full include-list for tests/cxx/ctad.cc:
+#include "tests/cxx/ctad-i1.h" // for Deduced
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/iwyu_stricter_than_cpp-type_alias.h b/tests/cxx/iwyu_stricter_than_cpp-type_alias.h
new file mode 100644
index 0000000..3256f55
--- /dev/null
+++ b/tests/cxx/iwyu_stricter_than_cpp-type_alias.h
@@ -0,0 +1,76 @@
+//===--- iwyu_stricter_than_cpp-type_alias.h - test input file for iwyu ---===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// The two rules the author has to follow to disable iwyu's
+// stricter-than-C++ rule and force it to fall back on the c++
+// requirement (forward-declare ok):
+// (1) forward-declare the relevant type
+// (2) do not directly #include the definition of the relevant type.
+
+#include "tests/cxx/iwyu_stricter_than_cpp-d1.h"
+
+// --- Type aliases.
+
+// Requires the full type because it does not obey rule (1)
+// IWYU: IndirectStruct1 is...*iwyu_stricter_than_cpp-i1.h
+using DoesNotForwardDeclareAl = IndirectStruct1;
+
+// This also does not obey rule (1): it's -d1 that does the fwd-declaring.
+// IWYU: IndirectStructForwardDeclaredInD1 is...*iwyu_stricter_than_cpp-i1.h
+using DoesNotForwardDeclareProperlyAl = IndirectStructForwardDeclaredInD1;
+
+// Requires the full type because it does not obey rule (2)
+struct DirectStruct1;
+using IncludesAl = DirectStruct1;
+
+// Requires the full type because it does not obey rules (1) *or* (2)
+using DoesNotForwardDeclareAndIncludesAl = DirectStruct2;
+
+// Does not require full type because it obeys all the rules.
+struct IndirectStruct2;
+using DoesEverythingRightAl = IndirectStruct2;
+
+// --- Now do it all again, with templates!
+
+// IWYU: TplIndirectStruct1 is...*iwyu_stricter_than_cpp-i1.h
+using TplDoesNotForwardDeclareAl = TplIndirectStruct1<int>;
+
+using TplDoesNotForwardDeclareProperlyAl
+// IWYU: TplIndirectStructForwardDeclaredInD1 is...*iwyu_stricter_than_cpp-i1.h
+ = TplIndirectStructForwardDeclaredInD1<int>;
+
+template <typename T> struct TplDirectStruct1;
+using TplIncludesAl = TplDirectStruct1<int>;
+
+using TplDoesNotForwardDeclareAndIncludesAl = TplDirectStruct2<int>;
+
+template <typename T> struct TplIndirectStruct2;
+using TplDoesEverythingRightAl = TplIndirectStruct2<int>;
+
+// Another way to forward-declare a class template.
+template <> struct TplIndirectStruct2<float>;
+using TplDoesEverythingRightAgainAl = TplIndirectStruct2<float>;
+
+
+/**** IWYU_SUMMARY
+
+tests/cxx/iwyu_stricter_than_cpp-type_alias.h should add these lines:
+#include "tests/cxx/iwyu_stricter_than_cpp-i1.h"
+
+tests/cxx/iwyu_stricter_than_cpp-type_alias.h should remove these lines:
+- struct DirectStruct1; // lines XX-XX
+- template <typename T> struct TplDirectStruct1; // lines XX-XX
+
+The full include-list for tests/cxx/iwyu_stricter_than_cpp-type_alias.h:
+#include "tests/cxx/iwyu_stricter_than_cpp-d1.h" // for DirectStruct1, DirectStruct2, TplDirectStruct1, TplDirectStruct2
+#include "tests/cxx/iwyu_stricter_than_cpp-i1.h" // for IndirectStruct1, IndirectStructForwardDeclaredInD1, TplIndirectStruct1, TplIndirectStructForwardDeclaredInD1
+struct IndirectStruct2; // lines XX-XX
+template <typename T> struct TplIndirectStruct2; // lines XX-XX
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/iwyu_stricter_than_cpp.cc b/tests/cxx/iwyu_stricter_than_cpp.cc
index d6f70d8..2bfa1c1 100644
--- a/tests/cxx/iwyu_stricter_than_cpp.cc
+++ b/tests/cxx/iwyu_stricter_than_cpp.cc
@@ -10,6 +10,7 @@
// IWYU_ARGS: -Xiwyu --check_also="tests/cxx/*-autocast.h" \
// -Xiwyu --check_also="tests/cxx/*-fnreturn.h" \
// -Xiwyu --check_also="tests/cxx/*-typedefs.h" \
+// -Xiwyu --check_also="tests/cxx/*-type_alias.h" \
// -Xiwyu --check_also="tests/cxx/*-d2.h" \
// -I .
@@ -36,6 +37,7 @@
// when these two conditions are met, and not otherwise.
#include "tests/cxx/iwyu_stricter_than_cpp-typedefs.h"
+#include "tests/cxx/iwyu_stricter_than_cpp-type_alias.h"
#include "tests/cxx/iwyu_stricter_than_cpp-autocast.h"
#include "tests/cxx/iwyu_stricter_than_cpp-fnreturn.h"
// We include this so the second declaration of TwiceDeclaredFunction
@@ -81,6 +83,39 @@ void TestTypedefs() {
// all) of the template args as well.
}
+using DoubleTypedefAl = DoesEverythingRightAl;
+
+void TestTypeAliases() {
+ DoesNotForwardDeclareAl dnfd(1);
+ DoesNotForwardDeclareProperlyAl dnfdp(2);
+ IncludesAl i(3);
+ DoesNotForwardDeclareAndIncludesAl dnfdai(4);
+ // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
+ DoesEverythingRightAl dor(5);
+ // Because DoubleTypedefAl resolves to DoesEverythingRightAl, we need the
+ // same things DoesEverythingRightAl does.
+ // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
+ DoubleTypedefAl dt(6);
+
+ // ...and with templates.
+ TplDoesNotForwardDeclareAl tdnfd(7);
+ TplDoesNotForwardDeclareProperlyAl tdnfdp(8);
+ TplIncludesAl ti(9);
+ TplDoesNotForwardDeclareAndIncludesAl tdnfdai(10);
+ // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
+ TplDoesEverythingRightAl tdor(11);
+ // IWYU: TplIndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
+ TplDoesEverythingRightAgainAl tdora(12);
+
+ // But if we're in a forward-declare context, we don't require the
+ // underlying type!
+ DoesEverythingRightAl* dor_ptr = 0;
+ TplDoesEverythingRightAgainAl* tdora_ptr = 0;
+ // ...at least until we dereference the pointer
+ // IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
+ (void) dor_ptr->a;
+}
+
void TestAutocast() {
// We need full type of is2 because the declarer of Fn didn't
// IWYU: IndirectStruct2 is...*iwyu_stricter_than_cpp-i2.h
@@ -159,6 +194,7 @@ The full include-list for tests/cxx/iwyu_stricter_than_cpp.cc:
#include "tests/cxx/iwyu_stricter_than_cpp-autocast.h" // for Fn, TplFn
#include "tests/cxx/iwyu_stricter_than_cpp-fnreturn.h" // for DoesEverythingRightFn, DoesNotForwardDeclareAndIncludesFn, DoesNotForwardDeclareFn, DoesNotForwardDeclareProperlyFn, IncludesFn, TplDoesEverythingRightAgainFn, TplDoesEverythingRightFn, TplDoesNotForwardDeclareAndIncludesFn, TplDoesNotForwardDeclareFn, TplDoesNotForwardDeclareProperlyFn, TplIncludesFn
#include "tests/cxx/iwyu_stricter_than_cpp-i2.h" // for IndirectStruct2, TplIndirectStruct2
+#include "tests/cxx/iwyu_stricter_than_cpp-type_alias.h" // for DoesEverythingRightAl, DoesNotForwardDeclareAl, DoesNotForwardDeclareAndIncludesAl, DoesNotForwardDeclareProperlyAl, IncludesAl, TplDoesEverythingRightAgainAl, TplDoesEverythingRightAl, TplDoesNotForwardDeclareAl, TplDoesNotForwardDeclareAndIncludesAl, TplDoesNotForwardDeclareProperlyAl, TplIncludesAl
#include "tests/cxx/iwyu_stricter_than_cpp-typedefs.h" // for DoesEverythingRight, DoesNotForwardDeclare, DoesNotForwardDeclareAndIncludes, DoesNotForwardDeclareProperly, Includes, TplDoesEverythingRight, TplDoesEverythingRightAgain, TplDoesNotForwardDeclare, TplDoesNotForwardDeclareAndIncludes, TplDoesNotForwardDeclareProperly, TplIncludes
struct DirectStruct1;
struct DirectStruct2;
diff --git a/tests/cxx/libbuiltins-direct.h b/tests/cxx/libbuiltins-direct.h
new file mode 100644
index 0000000..47afdf6
--- /dev/null
+++ b/tests/cxx/libbuiltins-direct.h
@@ -0,0 +1,10 @@
+//===--- libbuiltins-direct.h - test input file for iwyu ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <cmath>
diff --git a/tests/cxx/libbuiltins.cc b/tests/cxx/libbuiltins.cc
new file mode 100644
index 0000000..d2cdd3e
--- /dev/null
+++ b/tests/cxx/libbuiltins.cc
@@ -0,0 +1,34 @@
+//===--- libbuiltins.cc - test input file for iwyu ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Library builtins are, like normal builtins, compiled down to an intrinsic,
+// but a header still needs to be included for the program to be valid. The math
+// library (std::pow, std::round, etc) is a typical example.
+
+// IWYU_ARGS: -I .
+
+#include "tests/cxx/libbuiltins-direct.h"
+
+float kapow(float x) {
+ // IWYU: std::pow is...*cmath
+ return std::pow(x, 2.0F);
+}
+
+/**** IWYU_SUMMARY
+
+tests/cxx/libbuiltins.cc should add these lines:
+#include <cmath>
+
+tests/cxx/libbuiltins.cc should remove these lines:
+- #include "tests/cxx/libbuiltins-direct.h" // lines XX-XX
+
+The full include-list for tests/cxx/libbuiltins.cc:
+#include <cmath> // for pow
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/macro_location_tpl-d1.h b/tests/cxx/macro_location_tpl-d1.h
new file mode 100644
index 0000000..cf7712f
--- /dev/null
+++ b/tests/cxx/macro_location_tpl-d1.h
@@ -0,0 +1,10 @@
+//===--- macro_location_tpl-d1.h - test input file for iwyu ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "tests/cxx/macro_location_tpl-i1.h"
diff --git a/tests/cxx/macro_location_tpl-d2.h b/tests/cxx/macro_location_tpl-d2.h
new file mode 100644
index 0000000..33da0bb
--- /dev/null
+++ b/tests/cxx/macro_location_tpl-d2.h
@@ -0,0 +1,33 @@
+//===--- macro_location_tpl-d2.h - test input file for iwyu ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Declare a couple of function templates whose specializations are used in a
+// macro, to check that author intent hints attribute uses to the right place.
+template <typename>
+void expansion_template() = delete;
+template <>
+void expansion_template<int>();
+
+template <typename>
+void spelling_template() = delete;
+template <>
+void spelling_template<int>();
+
+// As above, but for class templates.
+template <typename>
+struct ExpansionTemplate {
+ void method() {
+ }
+};
+
+template <typename>
+struct SpellingTemplate {
+ void method() {
+ }
+};
diff --git a/tests/cxx/macro_location_tpl-i1.h b/tests/cxx/macro_location_tpl-i1.h
new file mode 100644
index 0000000..460e2a5
--- /dev/null
+++ b/tests/cxx/macro_location_tpl-i1.h
@@ -0,0 +1,30 @@
+//===--- macro_location_tpl-i1.h - test input file for iwyu ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Forward-declare the primary templates as a signal that specialization uses
+// belong in the expansion location.
+template <typename>
+void expansion_template();
+
+template <typename>
+class ExpansionTemplate;
+
+// expansion_template should be attributed to expansion loc.
+#define FUNC_TEMPLATE_SPEC_EXPANSION expansion_template<int>()
+
+// spelling_template should be attributed to this file, because there's no
+// forward-declare hint.
+#define FUNC_TEMPLATE_SPEC_SPELLING spelling_template<int>();
+
+// ExpansionTemplate should be attributed to expansion loc.
+#define CLASS_TEMPLATE_SPEC_EXPANSION ExpansionTemplate<int>().method();
+
+// SpellingTemplate should be attributed to this file, because there's no
+// forward-declare hint.
+#define CLASS_TEMPLATE_SPEC_SPELLING SpellingTemplate<int>().method();
diff --git a/tests/cxx/macro_location_tpl.cc b/tests/cxx/macro_location_tpl.cc
new file mode 100644
index 0000000..01a0a00
--- /dev/null
+++ b/tests/cxx/macro_location_tpl.cc
@@ -0,0 +1,46 @@
+//===--- macro_location_tpl.cc - test input file for iwyu -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// Expands on macro_location test case to also cover template scenarios. Macro
+// uses are attributed to spelling location, but forward-declarations of primary
+// templates also work as author intent hints for template specializations used
+// inside the macro.
+
+// IWYU_ARGS: -I .
+
+#include "tests/cxx/macro_location_tpl-d2.h"
+#include "tests/cxx/macro_location_tpl-d1.h"
+
+void use_macro_with_template_spec() {
+ // IWYU: FUNC_TEMPLATE_SPEC_EXPANSION is defined...*macro_location_tpl-i1.h
+ FUNC_TEMPLATE_SPEC_EXPANSION;
+
+ // IWYU: FUNC_TEMPLATE_SPEC_SPELLING is defined...*macro_location_tpl-i1.h
+ FUNC_TEMPLATE_SPEC_SPELLING;
+
+ // IWYU: CLASS_TEMPLATE_SPEC_EXPANSION is defined...*macro_location_tpl-i1.h
+ CLASS_TEMPLATE_SPEC_EXPANSION;
+
+ // IWYU: CLASS_TEMPLATE_SPEC_SPELLING is defined...*macro_location_tpl-i1.h
+ CLASS_TEMPLATE_SPEC_SPELLING;
+}
+
+/**** IWYU_SUMMARY
+
+tests/cxx/macro_location_tpl.cc should add these lines:
+#include "tests/cxx/macro_location_tpl-i1.h"
+
+tests/cxx/macro_location_tpl.cc should remove these lines:
+- #include "tests/cxx/macro_location_tpl-d1.h" // lines XX-XX
+
+The full include-list for tests/cxx/macro_location_tpl.cc:
+#include "tests/cxx/macro_location_tpl-d2.h" // for ExpansionTemplate, expansion_template
+#include "tests/cxx/macro_location_tpl-i1.h" // for CLASS_TEMPLATE_SPEC_EXPANSION, CLASS_TEMPLATE_SPEC_SPELLING, FUNC_TEMPLATE_SPEC_EXPANSION, FUNC_TEMPLATE_SPEC_SPELLING
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/no_forced_alias_callability-d1.h b/tests/cxx/no_forced_alias_callability-d1.h
new file mode 100644
index 0000000..895a73f
--- /dev/null
+++ b/tests/cxx/no_forced_alias_callability-d1.h
@@ -0,0 +1,14 @@
+//===--- no_forced_alias_callability-d1.h - test input file for iwyu ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+struct ReturnType;
+
+struct Aliased {
+ ReturnType doSomething();
+};
diff --git a/tests/cxx/no_forced_alias_callability-d2.h b/tests/cxx/no_forced_alias_callability-d2.h
new file mode 100644
index 0000000..7be9a1b
--- /dev/null
+++ b/tests/cxx/no_forced_alias_callability-d2.h
@@ -0,0 +1,18 @@
+//===--- no_forced_alias_callability-d2.h - test input file for iwyu ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+struct Aliased;
+
+typedef Aliased Alias;
+
+/**** IWYU_SUMMARY
+
+(tests/cxx/no_forced_alias_callability-d2.h has correct #includes/fwd-decls)
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/no_forced_alias_callability.cc b/tests/cxx/no_forced_alias_callability.cc
new file mode 100644
index 0000000..6d4ce0a
--- /dev/null
+++ b/tests/cxx/no_forced_alias_callability.cc
@@ -0,0 +1,29 @@
+//===--- no_forced_alias_callability.cc - test input file for iwyu --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// IWYU_ARGS: -Xiwyu --check_also="tests/cxx/no_forced_alias_callability-d2.h" \
+// -I .
+
+// Tests that IWYU doesn't require inclusion of an aliased class header
+// (...-d1.h) into a header with the alias to provide callability of methods
+// of the aliased class if the aliased class is explicitly made forward declared
+// in accordance with the IWYU policy
+
+#include "tests/cxx/no_forced_alias_callability-d1.h"
+#include "tests/cxx/no_forced_alias_callability-d2.h"
+
+int main() {
+ Alias a;
+}
+
+/**** IWYU_SUMMARY
+
+(tests/cxx/no_forced_alias_callability.cc has correct #includes/fwd-decls)
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/scope_crash.cc b/tests/cxx/scope_crash.cc
new file mode 100644
index 0000000..1659e08
--- /dev/null
+++ b/tests/cxx/scope_crash.cc
@@ -0,0 +1,45 @@
+//===--- scope_crash.cc - test input file for iwyu ------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// This is a weak testcase, but it's the smallest example we've found to
+// reproduce an IWYU crash where Sema::TUScope was unexpectedly null.
+//
+// For some reason libstdc++9's std::map with a value with explicit default
+// constructor triggers some path in Sema's constructor lookup that needs a
+// non-null TUScope.
+//
+// Clang or libstdc++ might change so that this can no longer trigger the
+// original bug, or so that the bug manifests some other way. But testers can't
+// be choosers.
+
+#include <string>
+#include <map>
+
+struct A {};
+
+bool operator<(const A& lhs, const A& rhs) {
+ return false;
+}
+
+struct B {
+ // Used to crash with libstdc++ 9, worked without 'explicit'
+ explicit B() = default;
+ std::string data;
+};
+
+void foo(const A& a) {
+ std::map<A, B> m;
+ m.erase(a);
+}
+
+/**** IWYU_SUMMARY
+
+(tests/cxx/scope_crash.cc has correct #includes/fwd-decls)
+
+***** IWYU_SUMMARY */
diff --git a/tests/cxx/update_comments.cc b/tests/cxx/update_comments.cc
new file mode 100644
index 0000000..bf0eccb
--- /dev/null
+++ b/tests/cxx/update_comments.cc
@@ -0,0 +1,28 @@
+//===--- update_comments.cc - test input file for iwyu --------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+// IWYU_ARGS: -Xiwyu --update_comments -I .
+
+// Test that passing the --update_comments switch to IWYU makes it always print
+// the full include-list, with up to date "// for XYZ" comments.
+
+#include "tests/cxx/indirect.h" // for SomethingElse
+
+IndirectClass indirect;
+
+/**** IWYU_SUMMARY
+
+tests/cxx/update_comments.cc should add these lines:
+
+tests/cxx/update_comments.cc should remove these lines:
+
+The full include-list for tests/cxx/update_comments.cc:
+#include "tests/cxx/indirect.h" // for IndirectClass
+
+***** IWYU_SUMMARY */