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
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 */
|