diff options
author | Kim Gräsman <kim@mvps.org> | 2013-06-19 11:24:25 +0000 |
---|---|---|
committer | Kim Gräsman <kim@mvps.org> | 2013-06-19 11:24:25 +0000 |
commit | 9615af8768012d30e0379c66c09e39886b813bee (patch) | |
tree | ad5d7378473fa8fd438c3a9c25101d535a10ca3d | |
parent | b1368d82903fce243318b8477c7099ce20903f20 (diff) |
Tag Clang 3.2 release branch.clang_3.2
-rw-r--r-- | CMakeLists.txt | 82 | ||||
-rw-r--r-- | Makefile | 11 | ||||
-rw-r--r-- | README.txt | 1479 | ||||
-rwxr-xr-x | fix_includes.py | 35 | ||||
-rw-r--r-- | gcc.stl.headers.imp | 14 | ||||
-rw-r--r-- | google.imp | 8 | ||||
-rw-r--r-- | iwyu.cc | 116 | ||||
-rw-r--r-- | iwyu_ast_util.cc | 43 | ||||
-rw-r--r-- | iwyu_ast_util.h | 5 | ||||
-rw-r--r-- | iwyu_driver.cc | 5 | ||||
-rw-r--r-- | iwyu_globals.cc | 28 | ||||
-rw-r--r-- | iwyu_globals.h | 4 | ||||
-rw-r--r-- | iwyu_include_picker.cc | 840 | ||||
-rw-r--r-- | iwyu_include_picker.h | 59 | ||||
-rw-r--r-- | iwyu_path_util.cc | 54 | ||||
-rw-r--r-- | iwyu_path_util.h | 10 | ||||
-rw-r--r-- | iwyu_preprocessor.cc | 20 | ||||
-rw-r--r-- | iwyu_preprocessor.h | 37 | ||||
-rwxr-xr-x | iwyu_test_util.py | 33 | ||||
-rw-r--r-- | make_readme.py | 142 | ||||
-rw-r--r-- | port.h | 34 | ||||
-rwxr-xr-x | run_iwyu_tests.py | 21 | ||||
-rw-r--r-- | tests/auto_type_within_template.cc | 22 | ||||
-rw-r--r-- | tests/badinc.imp | 5 | ||||
-rw-r--r-- | tests/conversion_ctor.cc | 38 | ||||
-rw-r--r-- | tests/cvr-base.h | 15 | ||||
-rw-r--r-- | tests/cvr-class.h | 15 | ||||
-rw-r--r-- | tests/cvr-derived.h | 17 | ||||
-rw-r--r-- | tests/cvr.cc | 49 | ||||
-rw-r--r-- | tests/keep_mapping.imp | 5 |
30 files changed, 707 insertions, 2539 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index def41e3..5bcd497 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,50 +1,10 @@ -cmake_minimum_required(VERSION 2.8) - project(include-what-you-use) -if( CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR ) - message(STATUS "IWYU out-of-tree configuration") - - if( NOT DEFINED LLVM_PATH ) - message(FATAL_ERROR "LLVM_PATH must be provided using -DLLVM_PATH=<path to llvm package root>") - endif() - - link_directories(${LLVM_PATH}/lib) - include_directories(${LLVM_PATH}/include) - - add_definitions( - -D__STDC_LIMIT_MACROS - -D__STDC_CONSTANT_MACROS - ) - - if( MSVC ) - # Adjust MSVC warning levels. - add_definitions( - # Ignore security warnings for standard functions. - -D_CRT_SECURE_NO_WARNINGS - -D_SCL_SECURE_NO_WARNINGS - - # Disabled warnings. - -wd4146 # Suppress 'unary minus operator applied to unsigned type, result still unsigned' - -wd4244 # Suppress ''argument' : conversion from 'type1' to 'type2', possible loss of data' - -wd4291 # Suppress ''declaration' : no matching operator delete found; memory will not be freed if initialization throws an exception' - -wd4345 # Suppress 'behavior change: an object of POD type constructed with an initializer of the form () will be default-initialized' - -wd4355 # Suppress ''this' : used in base member initializer list' - -wd4624 # Suppress ''derived class' : destructor could not be generated because a base class destructor is inaccessible' - -wd4800 # Suppress ''type' : forcing value to bool 'true' or 'false' (performance warning)' - - # Promoted warnings. - -w14062 # Promote 'enumerator in switch of enum is not handled' to level 1 warning. - - # Promoted warnings to errors. - -we4238 # Promote 'nonstandard extension used : class rvalue used as lvalue' to error. - ) - endif() -else() - message(STATUS "IWYU in-tree configuration") +if( MSVC ) + add_definitions( /D_POSIX_=1 ) endif() -add_executable(include-what-you-use +add_clang_executable(include-what-you-use iwyu.cc iwyu_ast_util.cc iwyu_cache.cc @@ -60,17 +20,6 @@ add_executable(include-what-you-use iwyu_verrs.cc ) -if( MSVC ) - # Put project in solution folder - set_target_properties(include-what-you-use - PROPERTIES FOLDER "Clang executables" - ) -else() - # Disable RTTI to be compatible with LLVM/Clang libraries. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti") -endif() - -# Clang dependencies. target_link_libraries(include-what-you-use clangFrontend clangSerialization @@ -79,38 +28,15 @@ target_link_libraries(include-what-you-use clangSema clangAnalysis clangAST + clangLex clangBasic clangEdit - clangLex ) -# LLVM dependencies. -target_link_libraries(include-what-you-use - LLVMipo - LLVMScalarOpts - LLVMInstCombine - LLVMTransformUtils - LLVMipa - LLVMAnalysis - LLVMTarget - LLVMMC - LLVMMCParser - LLVMCore - LLVMSupport - LLVMBitReader - LLVMOption -) - -# Platform dependencies. if( WIN32 ) target_link_libraries(include-what-you-use shlwapi ) -else() - target_link_libraries(include-what-you-use - pthread - dl - ) endif() install(TARGETS include-what-you-use @@ -23,18 +23,13 @@ NO_INSTALL = 1 TOOL_NO_EXPORTS = 1 include $(CLANG_LEVEL)/../../Makefile.config -LINK_COMPONENTS = $(TARGETS_TO_BUILD) asmparser bitreader ipo option +LINK_COMPONENTS = $(TARGETS_TO_BUILD) asmparser ipo USEDLIBS = clangFrontend.a clangSerialization.a clangDriver.a clangParse.a \ - clangSema.a clangAnalysis.a clangAST.a clangEdit.a clangLex.a \ - clangBasic.a + clangSema.a clangAnalysis.a clangAST.a clangLex.a clangBasic.a \ + clangEdit.a include $(CLANG_LEVEL)/Makefile -# Link with import library for shlwapi.dll on Windows. -ifneq (,$(filter $(HOST_OS), Cygwin MingW)) - LIBS += -lshlwapi -endif - check-iwyu:: all ./run_iwyu_tests.py ./fix_includes_test.py @@ -1,158 +1,151 @@ --------------------------------------------------------------------------------- - Include What You Use --------------------------------------------------------------------------------- - -This README was generated from the Wiki contents at -http://code.google.com/p/include-what-you-use/w/ on 2013-01-21 04:38:51 UTC. - - -= Instructions for Users = - -"Include what you use" means this: for every symbol (type, function, variable, -or macro) that you use in foo.cc (or foo.cpp), either foo.cc or foo.h should -#include a .h file that exports the declaration of that symbol. (Similarly, for -foo_test.cc, either foo_test.cc or foo.h should do the #including.) Obviously -symbols defined in foo.cc itself are excluded from this requirement. - -This puts us in a state where every file includes the headers it needs to -declare the symbols that it uses. When every file includes what it uses, then -it is possible to edit any file and remove unused headers, without fear of -accidentally breaking the upwards dependencies of that file. It also becomes -easy to automatically track and update dependencies in the source code. - - -== CAVEAT == - -This is alpha quality software -- at best (as of February 2011). It was written -to work specifically in the Google source tree, and may make assumptions, or -have gaps, that are immediately and embarrassingly evident in other types of -code. For instance, we only run this on C++ code, not C or Objective C. Even -for Google code, the tool still makes a lot of mistakes. - -While we work to get IWYU quality up, we will be stinting new features, and will -prioritize reported bugs along with the many existing, known bugs. The best -chance of getting a problem fixed is to submit a patch that fixes it (along with -a unittest case that verifies the fix)! - - -== How to Build == - -You will need the Clang and LLVM trees on your system, such as by checking out -their SVN trees (but don't configure or build before you've done the following.) - - * Put include-what-you-use in the source tree. Either download the include- -what-you-use tarball and unpack it your /path/to/llvm/tools/clang/tools -directory, or get the project directly from svn: - - # Unpack tarball - llvm/tools/clang/tools$ tar xfz include-what-you-use-<version>.tar.gz - - # or checkout from SVN - llvm/tools/clang/tools$ svn co http://include-what-you- -use.googlecode.com/svn/trunk/ include-what-you-use - - * Edit tools/clang/tools/Makefile and add include-what-you-use to the DIRS -variable - * Edit tools/clang/tools/CMakeLists.txt and add_subdirectory(include-what-you- -use) - * Once this is done, IWYU is recognized and picked up by both autoconf and -CMake workflows as described in the Clang Getting Started guide - -Include-what-you-use makes heavy use of Clang internals, and will occasionally -break when Clang is updated. See the include-what-you-use Makefile for -instructions on how to keep them in sync. - -IWYU, like Clang, does not yet handle some of the non-standard constructs in -Microsoft's STL headers. A discussion on how to use MinGW or Cygwin headers with -IWYU is available on the mailing list. - - -== How to Run == +==================== +Include What You Use +==================== + +"Include what you use" means this: for every symbol (type, function, +variable, or macro) that you use in foo.cc (or foo.cpp), either foo.cc +or foo.h should #include a .h file that exports the declaration of +that symbol. (Similarly, for foo_test.cc, either foo_test.cc or foo.h +should do the #including.) Obviously symbols defined in foo.cc itself +are excluded from this requirement. + +This puts us in a state where every file includes the headers it needs +to declare the symbols that it uses. When every file includes what it +uses, then it is possible to edit any file and remove unused headers, +without fear of accidentally breaking the upwards dependencies of that +file. It also becomes easy to automatically track and update +dependencies in the source code. + +====== +CAVEAT +====== + +This is alpha quality software -- at best. It was written to work +specifically in the Google source tree, and may make assumptions, or +have gaps, that are immediately and embarrassingly evident in other +types of code. For instance, we only run this on C++ code, not C or +Objective C. Even for Google code, the tool still makes a lot of +mistakes. + +While we work to get IWYU quality up, we will be stinting new +features, and will prioritize reported bugs along with the many +existing, known bugs. The best chance of getting a problem fixed is +to submit a patch that fixes it (along with a unittest case that +verifies the fix)! + +============ +How to Build +============ + +You will need the clang and llvm trees on your system, such as by +checking out their SVN trees: + http://clang.llvm.org/get_started.html + +Then download the include-what-you-use tarball and unpack it the +/path/to/llvm/tools/clang/tools directory: + llvm/tools/clang/tools$ tar xfz include-what-you-use-<whatever>.tar.gz +Or, alternately, get the project directly from svn: + llvm/tools/clang/tools$ svn co http://include-what-you-use.googlecode.com/svn/trunk/ include-what-you-use + +Then cd into the include-what-you-use directory (under tools) and type +'make'. + +Include what you use makes heavy use of clang internals, and will +occasionally break when clang is updated. For best results, download +clang as of the same revision number of the last include-what-you-use +release. You can find this revision number in comments at the top +of the include-what-you-use Makefile. + +-- BUILDING AGAINST LLVM 2.9 + +These are the commands I ran, which worked for me: + +1) Visit http://llvm.org/releases/download.html#2.9 +2) Download the appropriate binaries ("Clang Binaries for Linux/x86_64") +3) Untar the download file, cd to its root directory +4) Run this command: + g++ -D_DEBUG -D_GNU_SOURCE -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -fno-rtti -I include -L lib ~/devel/llvm/tools/clang/tools/include-what-you-use/*.cc -lclangFrontend -lclangSerialization -lclangDriver -lclangSema -lclangAnalysis -lclangAST -lclangParse -lclangLex -lclangBasic -lLLVMipo -lLLVMScalarOpts -lLLVMInstCombine -lLLVMTransformUtils -lLLVMipa -lLLVMAnalysis -lLLVMTarget -lLLVMMC -lLLVMCore -lLLVMSupport -lpthread -ldl -lm -o include-what-you-use + +========== +How to Run +========== The easiest way to run IWYU over your codebase is to run - - make -k CXX=/path/to/llvm/Debug+Asserts/bin/include-what-you-use - + make -k CXX=/path/to/llvm/Debug+Asserts/bin/include-what-you-use or + make -k CXX=/path/to/llvm/Release/bin/include-what-you-use - make -k CXX=/path/to/llvm/Release/bin/include-what-you-use - -(include-what-you-use always exits with an error code, so the build system knows -it didn't build a .o file. Hence the need for -k.) - -We also include, in this directory, a tool that automatically fixes up your -source files based on the iwyu recommendations. This is also alpha-quality -software! Here's how to use it (requires python): - - make -k CXX=/path/to/llvm/Debug+Asserts/bin/include-what-you-use > -/tmp/iwyu.out - python fix_includes.py < /tmp/iwyu.out - -If you don't like the way fix_includes.py munges your #include lines, you can -control its behavior via flags. fix_includes.py --help will give a full list, -but these are some common ones: +(include-what-you-use always exits with an error code, so the build +system knows it didn't build a .o file. Hence the need for -k.) - * -b: Put blank lines between system and Google #includes - * --nocomments: Don't add the 'why' comments next to #includes +We also include, in this directory, a tool that automatically fixes up +your source files based on the iwyu recommendations. This is also +alpha-quality software! Here's how to use it (requires python): -WARNING: include-what-you-use only analyzes .cc (or .cpp) files built by make, -along with their corresponding .h files. If your project has a .h file with no -corresponding .cc file, iwyu will ignore it. include-what-you-use supports the -AddGlobToReportIWYUViolationsFor() function which can be used to indicate other -files to analyze, but it's not currently exposed to the user in any way. + make -k CXX=/path/to/llvm/Debug+Asserts/bin/include-what-you-use > /tmp/iwyu.out + python fix_includes.py --nosafe < /tmp/iwyu.out +If you don't like the way fix_includes.py munges your #include lines, +you can control its behavior via flags. fix_includes.py --help will +give a full list, but these are some common ones: + * -b: Put blank lines between system and Google #includes + * --nocomments: Don't add the 'why' comments next to #includes -== How to Correct IWYU Mistakes == +WARNING: include-what-you-use only analyzes .cc (or .cpp) files built +by 'make', along with their corresponding .h files. If your project +has a .h file with no corresponding .cc file, iwyu will ignore it. +include-what-you-use supports the AddGlobToReportIWYUViolationsFor() +function which can be used to indicate other files to analyze, but +it's not currently exposed to the user in any way. - * If fix_includes.py has removed an #include you actually need, add it back in -with the comment '// IWYU pragma: keep' at the end of the #include line. Note -that the comment is case-sensitive. - * If fix_includes has added an #include you don't need, just take it out. We -hope to come up with a more permanent way of fixing later. - * If fix_includes has wrongly added or removed a forward-declare, just fix it -up manually. - * If fix_includes has suggested a private header file (such as -<bits/stl_vector.h>) instead of the proper public header file (<vector>), you -can fix this by inserting a specially crafted comment near top of the private -file (assuming you can write to it): '// IWYU pragma: private, include -"the/public/file.h"'. +============================ +How to Correct IWYU Mistakes +============================ -All current IWYU pragmas (as of July 2012) are described in [IWYUPragmas]. +1) If fix_includes.py has removed an #include you actually need, add + it back in with the comment '// IWYU pragma: keep' at the end of + the #include line. Note that the comment is case-sensitive. +2) If fix_includes has added an #include you don't need, just take it + out. We hope to come up with a more permanent way of fixing later. -= Instructions for Developers = +3) If fix_includes has wrongly added or removed a forward-declare, + just fix it up manually. -== Submitting Patches == +4) If fix_includes has suggested a private header file (such as + <bits/stl_vector.h>) instead of the proper public header file + (<vector>), you can fix this by inserting this comment near the + top of the private file (assuming you can write to it): + // IWYU pragma: private, include "the/public/file.h" + The full list of 'iwyu pragma' comments are at the top of + iwyu_preprocessor.h. -We're still working this part out. For now, you can create patches against svn- -head and submit them as new issues. Probably, we'll move to a scheme where -people can submit patches directly to the SVN repository. +================= +Running the Tests +================= +To run the iwyu tests, run + python run_iwyu_tests.py -== Running the Tests == +It runs one test for each .cc file in the tests/ directory. (We have +additional tests in more_tests/, but have not yet gotten the testing +framework set up for those tests.) The output can be a bit hard to +read, but if a test fails, the reason why will be listed after the +'ERROR:root:Test failed for xxx' line. If fixing a bug in clang, please add a test to the test suite! You -can create a file called whatever.cc (_not_ .cpp), and, if necessary, -whatever.h, and whatever-<extension>.h. You may be able to get away without -adding any .h files, and just #including direct.h -- see, for instance, +can create a file called whatever.cc (*not* .cpp), and whatever.h, and +whatever-<extension>.h. You may be able to get away without adding +any .h files, and just #including "direct.h" -- see, for instance, tests/remove_fwd_decl_when_including.cc. -To run the iwyu tests, run - - python run_iwyu_tests.py - -It runs one test for each .cc file in the tests/ directory. (We have additional -tests in more_tests/, but have not yet gotten the testing framework set up for -those tests.) The output can be a bit hard to read, but if a test fails, the -reason why will be listed after the -ERROR:root:Test failed for xxx line. +When fixing fix_includes.py, add a test case to fix_includes_test.py +and run + python fix_includes_test.py -When fixing fix_includes.py, add a test case to fix_includes_test.py and run - - python fix_includes_test.py - - -== Debugging == +========= +Debugging +========= It's possible to run include-what-you-use in gdb, to debug that way. Another useful tool -- especially in combination with gdb -- is to get @@ -160,1048 +153,294 @@ the verbose include-what-you-use output. See iwyu_output.h for a description of the verbose levels. Level 7 is very verbose -- it dumps basically the entire AST as it's being traversed, along with iwyu decisions made as it goes -- but very useful for that: + env IWYU_VERBOSE=7 make -k CXX=/path/to/llvm/Debug+Asserts/bin/include-what-you-use 2>&1 > /tmp/iwyu.verbose - env IWYU_VERBOSE=7 make -k CXX=/path/to/llvm/Debug+Asserts/bin/include-what- -you-use 2>&1 > /tmp/iwyu.verbose - - -== A Quick Tour of the Codebase == +=============== +Developer Notes +=============== The codebase is strewn with TODOs of known problems, and also language -constructs that aren't adequately tested yet. So there's plenty to do! Here's -a brief guide through the codebase: - - * iwyu.cc: the main file, it includes the logic for deciding when a symbol has -been 'used', and whether it's a full use (definition required) or forward- -declare use (only a declaration required). It also includes the logic for -following uses through template instantiations. - * iwyu_driver.cc: responsible for creating and configuring a Clang compiler -from command-line arguments. - * iwyu_output.cc: the file that translates from 'uses' into iwyu violations. -This has the logic for deciding if a use is covered by an existing #include (or -is a built-in). It also, as the name suggests, prints the iwyu output. - * iwyu_preprocessor.cc: handles the preprocessor directives, the #includes and -#ifdefs, to construct the existing include-tree. This is obviously essential -for include-what-you-use analysis. This file also handles the iwyu pragma- -comments. - * iwyu_include_picker.cc: this finds canonical #includes, handling -private->public mappings (like bits/stl_vector.h -> vector) and symbols with -multiple possible #includes (like NULL). Mappings are maintained in a set of -.imp files separately, for easier per-platform/-toolset customization. - * iwyu_cache.cc: holds the cache of instantiated templates (may hold other -cached info later). This is data that is expensive to compute and may be used -more than once. - * iwyu_globals.cc: holds various global variables. We used to think globals -were bad, until we saw how much having this file simplified the code... - * iwyu_*_util(s).h and .cc: utility functions of various types. The most -interesting, perhaps, is iwyu_ast_util.h, which has routines that make it -easier to navigate and analyze the clang AST. There are also some STL helpers, -string helpers, filesystem helpers, etc. - * iwyu_verrs.cc: debug logging for iwyu. - * port.h: shim header for various non-portable constructs. - * iwyu_getopt.cc: portability shim for GNU getopt(_long). Custom getopt(_long) -implementation for Windows. - * fix_includes.py: the helper script that edits a file based on the iwyu -recommendations. - - -= Why Include What You Use? = - -Are there any concrete benefits to a strict include-what-you-use policy? We like -to think so. - - -== Faster Compiles == - -Every .h file you bring in when compiling a source file lengthens the time to -compile, as the bytes have to be read, preprocessed, and parsed. If you're not -actually using a .h file, you remove that cost. With template code, where -entire instantiations have to be in .h files, this can be hundreds of thousands -of bytes of code. In one case at Google, running include-what-you-use over a -.cc file improved its compile time by 30%. - -Here, the main benefit of include-what-you-use comes from the flip side: "don't -include what you don't use." - - -== Fewer Recompiles == - -Many build tools, such as make, provide a mechanism for automatically figuring -out what .h files a .cc file depends on. These mechanisms typically look at -#include lines. When unnecessary #includes are listed, the build system is more -likely to recompile in cases where it's not necessary. - -Again, the main advantage here is from "don't include what you don't use." - - -== Allow Refactoring == - -Suppose you refactor foo.h so it no longer uses vectors. You'd like to remove -#include <vector> from foo.h, to reduce compile time -- template class files -such as vector can include a lot of code. But can you? In theory yes, but in -practice maybe not: some other file may be #including you and using vectors, and -depending (probably unknowingly) on your #include <vector> to compile. Your -refactor could break code far away from you. - -This is most compelling for a very large codebase (such as Google's). In a -small codebase, it's practical to just compile everything after a refactor like -this, and clean up any errors you see. When your codebase contains hundreds of -thousands of source files, identifying and cleaning up the errors can be a -project in itself. In practice, people are likely to just leave the #include -<vector> line in there, even though it's unnecessary. - -Here, it's the actual 'include what you use' policy that saves the day. If -everyone who uses vector is #including <vector> themselves, then you can remove -<vector> without fear of breaking anything. - - -== Self-documentation == - -When you can trust the #include lines to accurately reflect what is used in the -file, you can use them to help you understand the code. Looking at them, in -itself, can help you understand what this file needs in order to do its work. -If you use the optional 'commenting' feature of fix_includes.py, you can see -what symbols -- what functions and classes -- are used by this code. It's like -a pared-down version of doxygen markup, but totally automated and present where -the code is (rather than in a separate web browser). - -The 'commented' #include lines can also make it simpler to match function calls -and classes to the files that define them, without depending on a particular -IDE. - -(The downside, of course, is the comments can get out of date as the code -changes, so unless you run iwyu often, you still have to take the comments with -a grain of salt. Nothing is free. :-) ) - - -== Dependency Cutting == - -Again, this makes the most sense for large code-bases. Suppose your binaries -are larger than you would expect, and upon closer examination use symbols that -seem totally irrelevant. Where do they come from? Why are they there? With -include-what-you-use, you can easily determine this by seeing who #includes the -files that define these symbols: those includers, and those alone, are -responsible for the use. - -Once you know where a symbol is used in your binary, you can see how practical -it is to remove that use, perhaps by breaking up the relevant .h files into two -parts, and fixing up all callers. Again it's iwyu to the rescue: with include- -what-you-use, figuring out the callers that need fixing is easy. - - -== Why Forward-Declare? == - -Include-what-you-use tries very hard to figure out when a forward-declare can be -used instead of an #include (iwyu would be about 90% less code if it didn't -bother with trying to forward-declare). - -The reason for this is simple: if you can replace an #include by a forward- -declare, you reduce the code size, speeding up compiles as described above. You -also make it easier to break dependencies: not only do you not depend on that -#include file, you no longer depend on everything it brings in. - -There's a cost to forward-declaring as well: you lose the documentation features -mentioned above, that come with #include lines. (A future version of iwyu may -mitigate this problem.) And if a class changes -- for instance, it adds a new -default template argument -- you need to change many callsites, not just one. -It is also easier to accidentally violate the One Definition Rule when all you -expose is the name of a class (via a forward declare) rather than the full -definition (via an #include). - -One compromise approach is to use 'forwarding headers', such as <iosfwd>. These -forwarding headers could have comments saying where the definition of each -forward-declared class is. Include-what-you-use does not currently support -forwarding headers, but may in the future. - - -= IWYU Mappings = - -One of the difficult problems for IWYU is distinguishing between which header -contains a symbol definition and which header is the actual documented header to -include for that symbol. - -For example, in GCC's libstdc++, std::unique_ptr<T> is defined in -<bits/unique_ptr.h>, but the documented way to get it is to #include <memory>. - -Another example is NULL. Its authoritative header is <cstddef>, but for -practical purposes NULL is more of a keyword, and according to the standard it's -acceptable to assume it comes with <cstring>, <clocale>, <cwchar>, <ctime>, -<cstdio> or <cstdlib>. In fact, almost every standard library header pulls in -NULL one way or another, and we probably shouldn't force people to #include -<cstddef>. - -These mappings are all toolchain- and version-dependent. Symbol homes and -#include dependencies change between releases of GCC and are dramatically -different for the standard libraries shipped with Microsoft Visual C++. - -Finally, mappings such as these are usually necessary for third-party libraries -(e.g. Boost, Qt) or even project-local symbols and headers as well. - -The original design had mappings hard-coded in iwyu_include_picker.cc, which -made it difficult to experiment and almost impossible to create local or -alternative mappings. To ease porting to non-GCC platforms and make it easier -for users to test patches, we pulled the mappings out into external files parsed -at run-time. - -IWYU's original target environment was GCC, so the set of mapping files shipped -by default are currently very GCC-oriented. - - -== Mapping File Format == - -The mapping files conventionally use the .imp file extension, for "Iwyu -!MaPping" (terrible, I know). They use a JSON meta-format with the following -general form: - -[ - { <directive>: <data> }, - { <directive>: <data> } -] - -Directives can be one of the literal strings: - * include - * symbol - * ref - -and data varies between the directives, see below. - -Note that you can mix directives of different kinds within the same mapping -file. - -=== Include Mappings === - -The include directive specifies a mapping between two include names (relative -path, including quotes or angle brackets.) - -This is typically used to map from a private implementation detail header to a -public facade header, such as our <bits/unique_ptr.h> to <memory> example above. - -Data for this directive is a list of four strings containing: - * The include name to map from - * The visibility of the include name to map from - * The include name to map to - * The visibility of the include name to map to - -For example; - - { include: private, '<memory>', public } - -Most of the original mappings were generated with shell scripts (as evident from -the embedded comments) so there are several multi-step mappings from one private -header to another, to a third and finally to a public header. This reflects the -#include chain in the actual library headers. - -A hand-written mapping could be reduced to one mapping per private header to its -corresponding public header. - - -=== Symbol Mappings === - -The symbol directive maps from a qualified symbol name to its authoritative -header. - -Data for this directive is a list of four strings containing: - * The symbol name to map from - * The visibility of the symbol - * The include name to map to - * The visibility of the include name to map to - -For example; - - { symbol: private, '<cstddef>', public } - -The symbol visibility is largely redundant -- it must always be private. It -isn't entirely clear why symbol visibility needs to be specified, and it might -be removed moving forward. - - -=== Mapping Refs === - -The last kind of directive, ref, is used to pull in another mapping file, much -like the C preprocessor's #include directive. Data for this directive is a -single string: the filename to include. - -For example; - - { ref: more.symbols.imp }, - { ref: '/usr/lib/other.includes.imp' } - -The rationale for the ref directive was to make it easier to compose project- -specific mappings from a set of library-oriented mapping files. For example, -IWYU might ship with mapping files for Boost, the SCL, various C standard -libraries, the Windows API, the Poco Library, etc. Depending on what your -specific project uses, you could easily create an aggregate mapping file with -refs to the relevant mappings. - - -== Specifying Mapping Files == - -Mapping files are specified on the command-line using the --mapping_file switch: - - $ include-what-you-use -Xiwyu --mapping_file=foo.imp some_file.cc - -The switch can be added multiple times to add more than one mapping file. - -There is a single aggregate mapping called iwyu.gcc.imp which is the default -mapping used if nothing else is specified on the command-line. - -Both command-line arguments and ref directives use the same search path for -mapping files. They are, in order: - * The current directory, . - * The directory in which the include-what-you-use binary is located - * Any path from which a ref is loaded - -The last clause allows ref directives to be relative to the referring mapping -file. - - -= IWYU pragmas = - -IWYU pragmas are used to give IWYU information that isn't obvious from the -source code, such as how different files relate to each other and which -#includes to never remove or include. - -All pragmas start with "// IWYU pragma: " or "/* IWYU pragma: ". They are case- -sensitive and spaces are significant. - - -== IWYU pragma: keep == - -This pragma applies to a single #include statement. It forces IWYU to keep an -inclusion even if it is deemed unnecessary. - -main.cc: - #include <vector> // IWYU pragma: keep - -In this case, std::vector isn't used, so <vector> would normally be discarded, -but the pragma instructs IWYU to leave it. - - -== IWYU pragma: export == - -This pragma applies to a single #include statement. It says that the current -file is to be considered the provider of any symbol from the included file. - -facade.h: - #include "detail/constants.h" // IWYU pragma: export - #include "detail/types.h" // IWYU pragma: export - #include <vector> // don't export stuff from <vector> - -main.cc: - #include "facade.h" - - // Assuming Thing comes from detail/types.h and MAX_THINGS from -detail/constants.h - std::vector<Thing> things(MAX_THINGS); - -Here, since detail/constants.h and detail/types.h have both been exported, IWYU -is happy with the facade.h include for Thing and MAX_THINGS. - -In contrast, since <vector> has not been exported from facade.h, it will be -suggested as an additional include. - - -== IWYU pragma: begin_exports/end_exports == - -This pragma applies to a set of #include statements. It declares that the -including file is to be considered the provider of any symbol from these -included files. This is the same as decorating every #include statement with -IWYU pragma: export. - -facade.h: - // IWYU pragma: begin_exports - #include "detail/constants.h" - #include "detail/types.h" - // IWYU pragma: end_exports - - #include <vector> // don't export stuff from <vector> - - -== IWYU pragma: private == - -This pragma applies to the current header file. It says that any symbol from -this file will be provided by another, optionally named, file. - -private.h: - // IWYU pragma: private, include "public.h" - struct Private {}; - -private2.h: - // IWYU pragma: private - struct Private2 {}; - -public.h: - #include "private.h" - #include "private2.h" - -main.cc: - #include "private.h" - #include "private2.h" - - Private p; - Private2 i; - -Using the type Private in main.cc will cause IWYU to suggest that you include -public.h. - -Using the type Private2 in main.cc will cause IWYU to suggest that you include -private2.h, but will also result in a warning that there's no public header for -private2.h. - - -== IWYU pragma: no_include == - -This pragma applies to the current source file. It declares that the named file -should not be suggested for inclusion by IWYU. - -private.h: - struct Private {}; - -unrelated.h: - #include "private.h" - ... - -main.cc: - #include "unrelated.h" - // IWYU pragma: no_include "private.h" - - Private i; - -The use of Private requires including private.h, but due to the no_include -pragma IWYU will not suggest private.h for inclusion. Note also that if you had -included private.h in main.cc, IWYU would suggest that the #include be removed. - -This is useful when you know a symbol definition is already available via some -unrelated header, and you want to preserve that implicit dependency. - -The no_include pragma is somewhat similar to private, but is employed at point -of use rather than at point of declaration. - - -== IWYU pragma: no_forward_declare == - -This pragma applies to the current source file. It says that the named symbol -should not be suggested for forward-declaration by IWYU. - -public.h: - struct Public {}; - -unrelated.h: - struct Public; - ... - -main.cc: - #include "unrelated.h" // declares Public - // IWYU pragma: no_forward_declare Public - - Public* i; - -IWYU would normally suggest forward-declaring Public directly in main.cc, but -no_forward_declare suppresses that suggestion. A forward-declaration for Public -is already available from unrelated.h. - -This is useful when you know a symbol declaration is already available in a -source file via some unrelated header and you want to preserve that implicit -dependency, or when IWYU does not correctly understand that the definition is -necessary. - - -== IWYU pragma: friend == - -This pragma applies to the current header file. It says that any file matching -the given regular expression will be considered a friend, and is allowed to -include this header even if it's private. Conceptually similar to friend in C++. - -If the expression contains spaces, it must be enclosed in quotes. - -detail/private.h: - // IWYU pragma: private - // IWYU pragma: friend "detail/.*" - struct Private {}; - -detail/alsoprivate.h: - #include "detail/private.h" - - // IWYU pragma: private - // IWYU pragma: friend "main\.cc" - struct AlsoPrivate : Private {}; - -main.cc: - #include "detail/alsoprivate.h" - - AlsoPrivate p; - - -== Which pragma should I use? == - -Ideally, IWYU should be smart enough to understand your intentions (and -intentions of the authors of libraries you use), so the first answer should -always be: none. - -In practice, intentions are not so clear -- it might be ambiguous whether an -#include is there by clever design or by mistake, whether an #include serves to -export symbols from a private header through a public facade or if it's just a -left-over after some clean-up. Even when intent is obvious, IWYU can make -mistakes due to bugs or not-yet-implemented policies. - -IWYU pragmas have some overlap, so it can sometimes be hard to choose one over -the other. Here's a guide based on how I understand them at the moment: - - * Use IWYU pragma: keep to force IWYU to keep any #include statement that -would be discarded under its normal policies. - * Use IWYU pragma: export to tell IWYU that one header serves as the provider -for all symbols in another, included header (e.g. facade headers). Use IWYU -pragma: begin_exports/end_exports for a whole group of included headers. - * Use IWYU pragma: no_include to tell IWYU that the file in which the pragma -is defined should never #include a specific header (the header may already be -included via some other #include.) - * Use IWYU pragma: no_forward_declare to tell IWYU that the file in which the -pragma is defined should never forward-declare a specific symbol (a forward -declaration may already be available via some other #include.) - * Use IWYU pragma: private to tell IWYU that the header in which the pragma is -defined is private, and should not be included directly. - * Use IWYU pragma: private, include "public.h" to tell IWYU that the header in -which the pragma is defined is private, and public.h should always be included -instead. - * Use IWYU pragma: friend ".*favorites.*" to override IWYU pragma: private -selectively, so that a set of files identified by a regex can include the file -even if it's private. - -The pragmas come in three different classes; - - # Ones that apply to a single #include statement (keep, export) - # Ones that apply to a file being included (private, friend) - # Ones that apply to a file including other headers (no_include, -no_forward_declare) - -Some files are both included and include others, so it can make sense to mix and -match. - - -= What Is a Use? = - -(*Disclaimer:* the information here is accurate as of 12 May 2011, when it was -written. Specifics of IWYU's policy, and even philosophy, may have changed -since then. We'll try to remember to update this wiki page as that happens, but -may occassionally forget. The further we are from May 2011, the more you should -take the below with a grain of salt.) - -IWYU has the policy that you should #include a declaration for every symbol you -"use" in a file, or forward-declare it if possible. But what does it mean to -"use" a symbol? - -For the most part, IWYU considers a "use" the same as the compiler does: if you -get a compiler error saying "Unknown symbol 'foo'", then you are using foo. -Whether the use is a 'full' use, that needs the definition of the symbol, or a -'forward-declare' use, that can get by with just a declaration of the symbol, -likewise matches what the compiler allows. - -This makes it sound like IWYU does the moral equivalent of taking a source file, -removing #include lines from it, seeing what the compiler complains about, and -marking uses as appropriate. This is not what IWYU does. Instead, IWYU does a -thought experiment: if the definition (or declaration) of a given type were not -available, would the code compile? Here is an example illustrating the -difference: - -foo.h: - #include <ostream> - typedef ostream OutputEmitter; - -bar.cc: - #include "foo.h" - OutputEmitter oe; - oe << 5; - -Does bar.cc "use" ostream, such that it should #include <ostream>? You'd hope -the answer would be no: the whole point of the OutputEmitter typedef, -presumably, is to hide the fact the type is an ostream. Having to have clients -#include <ostream> rather defeats that purpose. But iwyu sees that you're -calling operator<<(ostream, int), which is defined in <ostream>, so naively, it -should say that you need that header. - -But IWYU doesn't (at least, modulo bugs). This is because of its attempt to -analyze "author intent". - - -== Author Intent == - -If code has typedef Foo MyTypedef, and you write MyTypedef var;, you are using -MyTypedef, but are you also using Foo? The answer depends on the _intent_ of -the person who wrote the typedef. - -In the OutputEmitter example above, while we don't know for sure, we can guess -that the intent of the author was that clients should not be considered to use -the underlying type -- and thus they shouldn't have to #include <ostream> -themselves. In that case, the typedef author takes responsibility for the -underlying type, promising to provide all the definitions needed to make code -compile. The philosophy here is: "As long as you #include foo.h, you can use -OutputEmitter however you want, without worry of compilation errors." - -Some typedef authors have a different intent. <iosfwd> has the line - - typedef basic_ostream<char> ostream; - -but it does *not* promise "as long as you #include <iosfwd>, you can use ostream -however you want, without worry of compilation errors." For most uses of -ostream, you'll get a compiler error unles you #include <ostream> as well. - -So take a slightly modified version of the above foo.h: - - #include <iosfwd> - typedef ostream OutputEmitter; - -This is a self-contained .h file: it's perfectly legal to typedef an incomplete -type (that's what iosfwd itself does). But now iwyu had better tell bar.cc to -#include <ostream>, or it will break the build. The difference is in the author -intent with the typedef. - -Another case where author intent turns up is in function return types. Consider -this function declaration: - - Foo* GetSingletonObject(); // Foo is defined in foo.h - -If you write GetSingletonObject()->methodOnFoo(), are you "using" -Foo::methodOnFoo, such that you should #include foo.h? Or are you supposed to -be able to operate on the results of GetSingletonObject without needing to -#include the definition of the returned type? The answer is: it depends on the -author intent. Sometimes the author is willing to provide the definition of the -return type, sometimes it is not. - - -=== Re-Exporting === - -When the author of a file is providing a definition of a symbol from somewhere -else, we say that the file is "re-exporting" that symbol. In the first -OutputEmitter example, we say that foo.h is re-exporting ostream. As a result, -people who #include foo.h get a definition of ostream along for free, even if -they don't directly #include <ostream> themselves. Another way of thinking -about it is: if file A re-exports symbol B, we can pretend that A defines B, -even if it doesn't. - -(In an ideal world, we'd have a very fine-grained concept: "File A re-exports -symbol S when it's used in the context of typedef T function F, or ...," but in -reality, we have the much looser concept "file A re-exports all symbols from -file B.") - -A more accurate include-what-you-use rule is this: "If you use a symbol, you -must either #include the definition of the symbol, or #include a file that re- -exports the symbol." - - -== Manual re-export identifiers == - -You can mark that one file is re-exporting symbols from another via an IWYU -pragma in your source code: - - #include "private.h" // IWYU pragma: export - -This tells IWYU that if some other file uses symbols defined in private.h, they -can #include you to get them, if they want. - -The full list of IWYU pragmas is defined at the top of iwyu_preprocessor.h. - - -== Automatic re-export == - -In certain situations, IWYU will decide that one file is exporting a symbol from -another even without the use of a pragma. These are places where the author -intent is usually to re-export, such as with the typedef example above. In each -of these cases, a simple technique can be used to override IWYU's decision to -re-export. - - -=== Automatic re-export: typedefs === - -If you write - - typedef Foo MyTypedef; - -IWYU has to decide whether your file should re-export Foo or not. Here is how -it gauges author intent: - - * If you (the typedef author), directly #include the definition of the -underlying type, then IWYU assumes you mean to re-export it. - * If you (the typedef author), explicitly provide a forward-declare of the -underlying type, but do not directly #include its definition, then IWYU assumes -you do not mean to re-export it. - * Otherwise, IWYU assumes you do not mean to re-export it. - - - #include "foo.h" - typedef Foo Typedef1; // IWYU says you intend to re-export Foo - - class Bar; - typedef Bar Typedef2; // IWYU says you do not intend to re-export Bar - - #include "file_including_baz.h" // does not define Baz itself - typedef Baz Typedef3; // IWYU says you do not intend to re-export Baz - -If iwyu says you intend to re-export the underlying type, then nobody who uses -your typedef needs to #include the definition of the underlying type. In -contrast, if iwyu says you do not intend to re-export the underlying type, then -everybody who uses your typedef needs to #include the definition of the -underlying type. - -IWYU supports this in its analysis. If you are using Typedef1 in your code and -#include "foo.h" anyway, iwyu will suggest you remove it, since you are getting -the definition of Foo via the typedef. - - -=== Automatic re-export: Function return values === - -The same rule applies with the return value in a function declaration: - - #include "foo.h" - Foo Func1(); // IWYU says you intend to re-export Foo - - class Bar; - Bar Func2(); // IWYU says you do not intend to re-export Bar - - #include "file_including_baz.h" - Baz Func3(); // IWYU says you do not intend to re-export Baz - -(Note that C++ is perfectly happy with a forward-declaration of the return type, -if the function is just being declared, and not defined.) - -As of May 2011, the rule does *not* apply when returning a pointer or reference: - - #include "foo.h" - Foo* Func1(); // IWYU says you do *not* intend to re-export Foo - - #include "bar.h" - Bar& Func2(); // IWYU says you do *not* intend to re-export Bar - -This is considered a bug, and the behavior will likely change in the future to -match the case where the functions return a class. - -Here is an example of the rule in action: - -foo.h: - class Foo { ... } - -bar.h: - #include "foo.h" - Foo CreateFoo() { ... } - void ConsumeFoo(const Foo& foo) { ... } - -baz.cc: - #include "bar.h" - ConsumeFoo(CreateFoo()); - -In this case, IWYU will say that baz.cc does not need to #include "foo.h", since -bar.h re-exports it. - - -=== Automatic re-export: Conversion constructors === - -Consider the following code: - -foo.h: - class Foo() { - Foo(int i) { ... }; // note: not an explicit constructor! - }; - -bar.h: - class Foo; - MyFunc(Foo foo); - -baz.cc: - #include "bar.h" - MyFunc(11); - -The above code does not compile, because the code to convert 11 to a Foo is not -visible to baz.cc. Either baz.cc or bar.h needs to #include "foo.h" to make the -conversion constructor visible where MyFunc is being called. - -The same rule applies as before: - - #include "foo.h" - Func1(Foo foo); // IWYU says you intend to re-export Foo - - class Foo; - Func2(Foo foo); // IWYU says you do not intend to re-export Foo - - #include "file_including_foo.h" - Func3(Foo foo); // IWYU says you do not intend to re-export Foo - -As before, if iwyu decides you do not intend to re-export Foo, then all callers -(in this case, baz.cc) need to. - -The rule here applies even to const references (which can also be automatically -converted): - - #include "foo.h" - Func1(const Foo& foo); // IWYU says you intend to re-export Foo - - - -= Why Include What You Use Is Difficult = - -This section is informational, for folks who are wondering why include-what-you- -use requires so much code and yet still has so many +constructs that aren't adequately tested yet. So there's plenty to +do! Here's a brief guide through the codebase: + +* iwyu.cc: the main file, it includes the logic for deciding when a + symbol has been 'used', and whether it's a full use (definition + required) or forward-declare use (only a declaration required). It + also inclues the logic for following uses through template + instantiations. + +* iwyu_output.cc: the file that translates from 'uses' into iwyu + violations. This has the logic for deciding if a use is covered by + an existing #include (or is a built-in). It also, as the name + suggests, prints the iwyu output. + +* iwyu_preprocessor.cc: handles the preprocessor directives, the + #includes and #ifdefs, to construct the existing include-tree. This + is obviously essential for include-what-you-use analysis. This file + also handles the iwyu pragma-comments. + +* iwyu_include_picker.cc: this finds canonical #includes, handling + hard-coded private->public mappings (like bits/stl_vector.h -> + vector) and symbols with multiple possible #includes (like NULL). + +* iwyu_cache.cc: holds the cache of instantiated templates (may hold + other cached info later). This is data that is expensive to compute + and may be used more than once. + +* iwyu_globals.cc: holds various global variables. We used to think + globals were bad, until we saw how much having this file simplified + the code... + +* iwyu_*_util(s).h and .cc: utility functions of various types. The + most interesting, perhaps, is iwyu_ast_util.h, which has routines + that make it easier to navigate and analyze the clang AST. There + are also some STL helpers, string helpers, filesystem helpers, etc. + +* fix_includes.py: the helper script that edits a file based on the + iwyu recommendations. + +===================== +Why IWYU is Difficult +===================== + +This last section is informational, for folks who are wondering why +include-what-you-use requires so much code and yet still has so many errors. -Include-what-you-use has the most problems with templates and macros. If your -code doesn't use either, iwyu will probably do great. And, you're probably not -actually programming in C++... - +Include-what-you-use has the most problems with templates and +macros. If your code doesn't use either, iwyu will probably do +great. And, you're probably not actually programming in C++... -== Use Versus Forward Declare == +USE VERSUS FORWARD DECLARE -Include-what-you-use has to be able to tell when a symbol is being used in a way -that you can forward-declare it. Otherwise, if you wrote +Include-what-you-use has to be able to tell when a symbol is being +used in a way that you can forward-declare it. Otherwise, if you wrote - vector<MyClass*> foo; + vector<MyClass*> foo; -iwyu would tell you to #include "myclass.h", when perhaps the whole reason -you're using a pointer here is to avoid the need for that #include. +iwyu would tell you to #include "myclass.h", when perhaps the whole +reason you're using a pointer here is to avoid the need for that +#include. -In the above case, it's pretty easy for iwyu to tell that we can safely forward- -declare MyClass. But now consider +In the above case, it's pretty easy for iwyu to tell that we can +safely forward-declare MyClass. But now consider - vector<MyClass> foo; // requires full definition of MyClass - scoped_ptr<MyClass> foo; // forward-declaring MyClass is often ok + vector<MyClass> foo; // requires full definition of MyClass + scoped_ptr<MyClass> foo; // forward-declaring MyClass is ok -To distinguish these, clang has to instantiate the vector and scoped_ptr -template classes, including analyzing all member variables +To distinguish these, clang has to instantiate the vector and +scoped_ptr template classes, including analyzing all member variables and the bodies of the constructor and destructor (and recursively for superclasses). -But that's not enough: when instantiating the templates, we need to keep track -of which symbols come from template arguments and which -don't. For instance, suppose you call MyFunc<MyClass>(), where MyFunc looks like -this: +But that's not enough: when instantiating the templates, we need to +keep track of which symbols come from template arguments and which +don't. For instance, suppose you call MyFunc<MyClass>(), where MyFunc +looks like this: - template<typename T> void MyFunc() { - T* t; - MyClass myclass; - ... - } + template<typename T> void MyFunc() { + T* t; + MyClass myclass; + ... + } -In this case, the caller of MyFunc is not using the full type of MyClass, -because the template parameter is only used as a pointer. On -the other hand, the file that defines MyFunc is using the full type information -for MyClass. The end result is that the caller can forward-declare MyClass, but -the file defining MyFunc has to #include "myclass.h". +In this case, the caller of MyFunc is not using the full type of +MyClass, because the template parameter is only used as a pointer. On +the other hand, the file that defines MyFunc is using the full type +information for MyClass. The end result is that the caller can +forward-declare MyClass, but the file defining MyFunc has to #include +"myclass.h". +HANDLING TEMPLATE ARGUMENTS -== Handling Template Arguments == +Even figuring out what types are 'used' with a template can be +difficult. Consider the following two declarations: -Even figuring out what types are 'used' with a template can be difficult. -Consider the following two declarations: - - vector<MyClass> v; - hash_set<MyClass> h; + vector<MyClass> v; + hash_set<MyClass> h; These both have default template arguments, so are parsed like - vector<MyClass, alloc<MyClass> > v; - hash_set<MyClass, hash<MyClass>, equal_to<MyClass>, alloc<MyClass> > h; + vector<MyClass, alloc<MyClass> > v; + hash_set<MyClass, hash<MyClass>, equal_to<MyClass>, alloc<MyClass> > h; -What symbols should we say are used? If we say alloc<MyClass> is used when you -declare a vector, then every file that #includes <vector> +What symbols should we say are used? If we say alloc<MyClass> is used +when you declare a vector, then every file that #includes <vector> will also need to #include <memory>. -So it's tempting to just ignore default template arguments. But that's not right -either. What if hash<MyClass> is defined in some local myhash.h file (as -hash<string> often is)? Then we want to make sure iwyu says to #include -"myhash.h" when you create the hash_set (otherwise the code won't compile). That -requires paying attention to the default template argument. Figuring out how to -handle default template arguments can get very complex. - -Even normal template arguments can be confusing. Consider this templated -function: +So it's tempting to just ignore default template arguments. But that's +not right either. What if hash<MyClass> is defined in some local +myhash.h file (as hash<string> often is)? Then we want to make sure iwyu +says to #include "myhash.h" when you create the hash_set +(otherwise the code won't compile). That requires paying attention to +the default template argument. Figuring out how to handle default +template arguments can get very complex. - template<typename A, typename B, typename C> void MyFunc(A (*fn)(B,C)) - { ... } +Even normal template arguments can be confusing. Consider this +templated function: -and you call MyFunc(FunctionReturningAFunctionPointer()). What types are being -used where, in this case? +template<typename A, typename B, typename C> void MyFunc(A (*fn)(B,C)) { ... } +and you call MyFunc(FunctionReturningAFunctionPointer()). What types +are being used where, in this case? -== Who is Responsible for Dependent Template Types? == +WHO IS RESPONSIBLE FOR DEPENDENT TEMPLATE TYPES? -If you say vector<MyClass> v;, it's clear that you, and not vector.h are -responsible for the use of MyClass, even though all the functions that use -MyClass are defined in vector.h. (OK, technically, these functions are not -"defined" in a particular location, they're instantiated from template methods -written in vector.h, but for us it works out the same.) +If you say vector<MyClass> v;, it's clear that you, and not vector.h, +are responsible for the use of MyClass, even though all the functions +that use MyClass are defined in vector.h. (OK, technically, these +functions are not "defined" in a particular location, they're +instantiated from template methods written in vector.h, but for us it +works out the same.) -When you say hash_map<MyClass, int> h;, you are likewise responsible for MyClass -(and int), but are you responsible for pair<MyClass, int>? That is the type that -hash_map uses to store your entries internally, and it depends on one of your -template arguments, but even so it shouldn't be your responsibility -- it's an -implementation detail of hash_map. Of course, if you say hash_map<pair<int, -int>, int>, then you are responsible for the use of pair. Distinguishing these -two cases from each other, and from the vector case, can be difficult. +When you say hash_map<MyClass, int> h;, you are likewise responsible +for MyClass (and int), but are you responsible for pair<MyClass, int>? +That is the type that hash_map uses to store your entries internally, +and it depends on one of your template arguments, but even so it +shouldn't be your responsibility -- it's an implementation detail of +hash_map. Of course, if you say hash_map<pair<int, int>, int>, then +you are responsible for the use of pair. Distinguishing these two +cases from each other, and from the vector case, can be difficult. Now suppose there's a template function like this: - template<typename T> void MyFunc(T t) { - strcat(t, 'a'); - strchr(t, 'a'); - cerr << t; - } + template<typename T> void MyFunc(T t) { + strcat(t, 'a'); + strchr(t, 'a'); + cerr << t; + } -If you call MyFunc(some_char_star), which of these symbols are you responsible -for, and which is the author of MyFunc responsible for: +If you call MyFunc(some_char_star), which of these symbols are you +responsible for, and which is the author of MyFunc responsible for: strcat, strchr, operator<<(ostream&, T)? -strcat is a normal function, and the author of MyFunc is responsible for its -use. This is an easy case. +strcat is a normal function, and the author of MyFunc is responsible +for its use. This is an easy case. -In C++, strchr is a templatized function (different impls for char* and const -char*). Which version is called depends on the template argument. So, naively, -we'd conclude that the caller is responsible for the use of strchr. However, -that's ridiculous; we don't want caller of MyFunc to have to #include <string.h> -just to call MyFunc. We have special code that (usually) handles this kind of -case. +In C++, strchr is a templatized function (different impls for char* +and const char*). Which version is called depends on the template +argument. So, naively, we'd conclude that the caller is responsible +for the use of strchr. However, that's ridiculous; we don't want every +caller of MyFunc to have to #include <string.h> just to call +MyFunc. We have special code that (usually) handles this kind of case. -operator<< is also a templated function, but it's one that may be defined in -lots of different files. It would be ridiculous in its own way if MyFunc was -responsible for #including every file that defines operator<<(ostream&, T) for -all T. So, unlike the two cases above, the caller is the one responsible for the -use of operator<<, and will have to #include the file that defines it. It's -counter-intuitive, perhaps, but the alternatives are all worse. +operator<< is also a templatized function, but it's one that may be +defined in lots of different files. It would be ridiculous in its own +way if MyFunc was responsible for #including every file that defines +operator<<(ostream&, T) for all T. So, unlike the two cases above, the +caller is the one responsible for the use of operator<<, and will have +to #include the file that defines it. It's counter-intuitive, perhaps, +but the alternatives are all worse. -As you can imagine, distinguishing all these cases is extremely difficult. To -get it exactly right would require re-implementing C++'s (byzantine) lookup -rules, which we have not yet tackled. +As you can imagine, distinguishing all these cases is extremely +difficult. To get it exactly right would require re-implementing C++'s +(byzantine) lookup rules, which we have not yet tackled. - -== Template Template Types == +TEMPLATE TEMPLATE TYPES Let's say you have a function - template<template<typename U> T> void MyFunc() { - T<string> t; - } - -And you call MyFunc<hash_set>. Who is responsible for the 'use' of hash<string>, -and thus needs to #include "myhash.h"? I think it has to be the caller, even if -the caller never uses the string type in its file at all. This is rather -counter-intuitive. Luckily, it's also rather rare. + template<template<typename U> T> void MyFunc() { + T<string> t; + } +and you call MyFunc<hash_set>(). Who is responsible for the 'use' of +hash<string>, and thus needs to #include "myhash.h"? I think +it has to be the caller, even if the caller never uses the string type +in its file at all. This is rather counter-intuitive. Luckily, it's +also rather rare. -== Typedefs == +TYPEDEFS -Suppose you #include a file "foo.h" that has typedef hash_map<Foo, Bar> MyMap;. -And you have this code: +Suppose you #include a file "foo.h" that has typedef hash_map<Foo, +Bar> MyMap;. And you have this code: - for (MyMap::iterator it = ...) + for (MyMap::iterator it = ...) -Who, if anyone, is using the symbol hash_map<Foo, Bar>::iterator? If we say you, -as the author of the for-loop, are the user, then you must #include <hash_map>, -which undoubtedly goes against the goal of the typedef (you shouldn't even have -to know you're using a hash_map). So we want to say the author of the typedef is -responsible for the use. But how could the author of the typedef know that you -were going to use MyMap::iterator? It can't predict that. That means it has to -be responsible for every possible use of the typedef type. This can be -complicated to figure out. It requires instantiating all methods of the -underlying type, some of which might not even be legal C++ (if, say, the class -uses SFINAE). +Who, if anyone, is using the symbol hash_map<Foo, Bar>::iterator? If +we say you, as the author of the for-loop, are the user, then you must +#include <hash_map>, which undoubtedly goes against the goal of the +typedef (you shouldn't even have to know you're using a hash_map). So +we want to say the author of the typedef is responsible for the +use. But how could the author of the typedef know that you were going +to use MyMap::iterator? It can't predict that. That means it has to be +responsible for every possible use of the typedef type. This can be +complicated to figure out. It requires instantiating all methods of +the underlying type, some of which might not even be legal C++ (if, +say, the class uses SFINAE). Worse, when the language auto-derives template types, it loses typedef information. Suppose you wrote this: - MyMap m; - find(m.begin(), m.end(), some_foo); + MyMap m; + find(m.begin(), m.end(), some_foo); -The compiler sees this as syntactic sugar for find<hash_map<Foo, Bar, hash<Foo>, -equal_to<Foo>, alloc<Foo> >(m.begin(), m.end(), some_foo); +The compiler sees this as syntactic sugar for find<hash_map<Foo, Bar, +hash<Foo>, equal_to<Foo>, alloc<Foo> >(m.begin(), m.end(), some_foo); -Not only is the template argument hash_map instead of MyMap, it includes all the -default template arguments, with no indication they're default arguments. All -the tricks we used above to intelligently ignore default template arguments are -worthless here. We have to jump through lots of hoops so this code doesn't -require you to #include not only <hash_map>, but <alloc> and <utility> as well. +Not only is the template argument hash_map instead of MyMap, it +includes all the default template arguments, with no indication +they're default arguments. All the tricks we used above to +intelligently ignore default template arguments are worthless here. We +have to jump through lots of hoops so this code doesn't require you to +#include not only <hash_map>, but <alloc> and <utility> as well. - -== Macros == +MACROS It's no surprise macros cause a huge problem for include-what-you-use. -Basically, all the problems of templates also apply to macros, but worse: with -templates you can analyze the uninstantiated template, but with macros, you -can't analyze the uninstantiated macro -- it likely doesn't even parse cleanly -in isolation. As a result, we have very few tools to distinguish when the author -of a macro is responsible for a symbol used in a macro, and when the caller of -the macro is responsible. - - -== Includes with Side Effects == - -While not a major problem, this indicates the myriad "gotchas" that exist around -include-what-you-use: removing an #include and replacing it with a forward- -declare may be dangerous even if no symbols are fully used from the #include. -Consider the following code: - -foo.h: - namespace ns { class Foo {}; } - using ns::Foo; - -foo.cc: - #include "foo.h" - Foo* foo; - -If iwyu just blindly replaces the #include with a forward declare such as -namespace ns { class Foo; }, the code will break because of the lost using -declaration. Include-what-you-use has to watch out for this case. - -Another case is a header file like this: - -foo.h: - #define MODULE_NAME MyModule - #include "module_writer.h" - -We might think we can remove an #include of foo.h and replace it by #include -module_writer.h, but that is likely to break the build if module_writer.h -requires MODULE_NAME be defined. Since my file doesn't participate in this -dependency at all, it won't even notice it. IWYU needs to keep track of -dependencies between files it's not even trying to analyze! - - -== Private Includes == - -Suppose you write vector<int> v;. You are using vector, and thus have to -#include <vector>. Even this seemingly easy case is difficult, because vector -isn't actually defined in <vector>; it's defined in <bits/stl_vector.h>. The C++ -standard library has hundreds of private files that users are not supposed to -#include directly. Third party libraries have hundreds more. There's no general -way to distinguish private from public headers; we have to manually construct -the proper mapping. - -In the future, we hope to provide a way for users to annotate if a file is -public or private, either a comment or a #pragma. For now, we hard-code it in -the iwyu tool. - -The mappings themselves can be ambiguous. For instance, NULL is provided by many -files, including stddef.h, stdlib.h, and more. If you use NULL, what #include -file should iwyu suggest? We have rules to try to minimize the number of -#includes you have to add; it can get rather involved. - - -== Unparsed Code == - -Conditional #includes are a problem for iwyu when the condition is false: - - #if _MSC_VER - #include <foo> - #endif - -If we're not running under windows (and iwyu does not currently run under -windows), we have no way of telling if foo is a necessary #include or not. - - -== Placing New Includes and Forward-Declares == - -Figuring out where to insert new #includes and forward-declares is a complex -problem of its own (one that is the responsibility of fix_includes.py). In -general, we want to put new #includes with existing #includes. But the existing -#includes may be broken up into sections, either because of conditional -#includes (with #ifdefs), or macros (such as #define __GNU_SOURCE), or for other -reasons. Some forward-declares may need to come early in the file, and some may -prefer to come later (after we're in an appropriate namespace, for instance). - -fix_includes.py tries its best to give pleasant-looking output, while being -conservative about putting code in a place where it might not compile. It uses -heuristics to do this, which are not yet perfect. +Basically, all the problems of templates also apply to macros, but +worse: we can analyze an uninstantiated template, but we can't analyze +an uninstantiated macro -- the macro likely doesn't even parse cleanly +in isolation. As a result, we have very few tools to distinguish when +the author of a macro is responsible for a symbol used in a macro, and +when the caller of the macro is responsible. + +PRIVATE INCLUDES + +Suppose you write vector<int> v;. You are using vector, and thus have +to #include <vector>. Even this seemingly easy case is difficult, +because vector isn't actually defined in <vector>; it's defined in +<bits/stl_vector.h>. The C++ standard library has hundreds of private +files that users are not supposed to #include directly. Third party +libraries have hundreds more. There's no general way to distinguish +private from public headers; we have to manually construct the proper +mapping. + +In the future, we hope to provide a way for users to annotate if a +file is public or private, either a comment or a #pragma. For now, we +hard-code it in the iwyu tool. + +The mappings themselves can be ambiguous. For instance, NULL is +provided by many files, including stddef.h, stdlib.h, and more. If you +use NULL, what #include file should iwyu suggest? We have rules to try +to minimize the number of #includes you have to add; it can get rather +involved. + +UNPARSED CODE + +Conditional #includes are a problem for iwyu when the condition is +false: + +#if _MSC_VER +#include <foo> +#endif + +If we're not running under windows (and iwyu does not currently run +under windows), we have no way of telling if foo is a necessary +#include or not. + +PLACING NEW INCLUDES AND FORWARD-DECLARES + +Figuring out where to insert new #includes and forward-declares is a +complex problem of its own (one that is the responsibility of +fix_includes.py). In general, we want to put new #includes with +existing #includes. But the existing #includes may be broken up into +sections, either because of conditional #includes (with #ifdefs), or +macros (such as #define __GNU_SOURCE), or for other reasons. Some +forward-declares may need to come early in the file, and some may +prefer to come later (after we're in an appropriate namespace, for +instance). + +fix_includes.py tries its best to give pleasant-looking output, while +being conservative about putting code in a place where it might not +compile. It uses heuristics to do this, which are not yet perfect. diff --git a/fix_includes.py b/fix_includes.py index 3a88750..36e44bb 100755 --- a/fix_includes.py +++ b/fix_includes.py @@ -145,12 +145,6 @@ _LINE_TYPES = [_COMMENT_LINE_RE, _BLANK_LINE_RE, # added; it just affects the reordering of existing #includes.) _BARRIER_INCLUDES = re.compile(r'^\s*#\s*include\s+(<linux/)') -# A list of all known extensions for C++ source files, used to -# guess if a filename is a source file or a header. -# Please keep this in sync with source_extensions in iwyu_path_util.cc. -_SOURCE_EXTENSIONS = [".c", ".C", ".cc", ".CC", ".cxx", ".CXX", - ".cpp", ".CPP", ".c++", ".C++", ".cp"] - def _MayBeHeaderFile(filename): """Tries to figure out if filename is a C++ header file. Defaults to yes.""" @@ -158,7 +152,7 @@ def _MayBeHeaderFile(filename): # extension at all. So we say everything is a header file unless it # has a known extension that's not. extension = os.path.splitext(filename)[1] - return extension not in _SOURCE_EXTENSIONS + return extension not in ('.c', '.cc', '.cxx', '.cpp', '.C', '.CC') class FixIncludesError(Exception): @@ -499,35 +493,18 @@ def _ReadWriteableFile(filename, ignore_writeable): return None -def _WriteFileContentsToFileObject(f, file_lines, line_ending): +def _WriteFileContentsToFileObject(f, file_lines): """Write the given file-lines to the file.""" - f.write(line_ending.join(file_lines)) - f.write(line_ending) - -def _DetectLineEndings(filename): - """Detect line ending of given file.""" + f.write('\n'.join(file_lines)) + f.write('\n') - # Find out which file ending is used first. The - # first lines indicate the line ending for the whole file - # so pathological files with mixed endings aren't handled properly! - f = open(filename, 'U') - try: - while f.newlines is None: - if f.readline() == '': - break - return f.newlines if f.newlines != None and \ - type(f.newlines) is not tuple else '\n' - finally: - f.close() def _WriteFileContents(filename, file_lines): """Write the given file-lines to the file.""" try: - line_ending = _DetectLineEndings(filename) - # Open file in binary mode to preserve line endings - f = open(filename, 'wb') + f = open(filename, 'w') try: - _WriteFileContentsToFileObject(f, file_lines, line_ending) + _WriteFileContentsToFileObject(f, file_lines) finally: f.close() except (IOError, OSError), why: diff --git a/gcc.stl.headers.imp b/gcc.stl.headers.imp index 625e448..99b6593 100644 --- a/gcc.stl.headers.imp +++ b/gcc.stl.headers.imp @@ -102,6 +102,9 @@ { include: ["<tr1_impl/cwctype>", private, "<tr1/cwctype>", public ] }, { include: ["<tr1_impl/functional>", private, "<functional>", public ] }, { include: ["<tr1_impl/functional>", private, "<tr1/functional>", public ] }, + { include: ["<tr1_impl/functional_hash.h>", private, + "<tr1/functional_hash.h>", public ] }, + { include: ["<tr1_impl/hashtable>", private, "<tr1/hashtable.h>", public ] }, { include: ["<tr1_impl/random>", private, "<random>", public ] }, { include: ["<tr1_impl/random>", private, "<tr1/random>", public ] }, { include: ["<tr1_impl/regex>", private, "<regex>", public ] }, @@ -117,17 +120,6 @@ # This didn't come from the grep, but seems to be where swap() # is defined? { include: ["<bits/move.h>", private, "<algorithm>", public ] }, # for swap<>() - # Hash and hashtable-based containers. - { include: ["<tr1_impl/functional_hash.h>", private, "<tr1/functional>", public ] }, - { include: ["<tr1_impl/functional_hash.h>", private, "<tr1/unordered_map>", public ] }, - { include: ["<tr1_impl/functional_hash.h>", private, "<tr1/unordered_set>", public ] }, - { include: ["<tr1/functional_hash.h>", private, "<tr1/functional>", public ] }, - { include: ["<tr1/functional_hash.h>", private, "<tr1/unordered_map>", public ] }, - { include: ["<tr1/functional_hash.h>", private, "<tr1/unordered_set>", public ] }, - { include: ["<tr1_impl/hashtable>", private, "<tr1/unordered_map>", public ] }, - { include: ["<tr1_impl/hashtable>", private, "<tr1/unordered_set>", public ] }, - { include: ["<tr1/hashtable.h>", private, "<tr1/unordered_map>", public ] }, - { include: ["<tr1/hashtable.h>", private, "<tr1/unordered_set>", public ] }, # All .tcc files are gcc internal-include files. We get them from # ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && grep -R '^ *# *include.*tcc' * | perl -nle 'm/^([^:]+).*[<"]([^>"]+)[>"]/ && print qq@ { include: ["<$2>", private, "<$1>", public ] },@' | sort ) # I had to manually edit some of the entries to say the map-to is private. diff --git a/google.imp b/google.imp new file mode 100644 index 0000000..409e6a9 --- /dev/null +++ b/google.imp @@ -0,0 +1,8 @@ +# Google-specific header mappings +[ + # These two are here just for unittesting. + { include: ["\"tests/badinc-private.h\"", private, "\"tests/badinc-inl.h\"", public] }, + { include: ["\"tests/badinc-private2.h\"", private, "\"tests/badinc-inl.h\"", public] }, + { include: ["@\"tests/keep_mapping-private.*\"", private, "\"tests/keep_mapping-public.h\"", public ] }, + { include: ["\"tests/keep_mapping-priv.h\"", private, "\"tests/keep_mapping-public.h\"", public ] } +] @@ -86,6 +86,12 @@ // case it is. For example, if foo.cc desires bar.h, but can // already get it via foo.h, IWYU won't recommend foo.cc to // #include bar.h, unless it already does so. + +#if defined(_MSC_VER) +#include <direct.h> +#else +#include <unistd.h> // for chdir +#endif #include <stddef.h> // for size_t #include <stdio.h> // for snprintf #include <stdlib.h> // for atoi, exit @@ -229,6 +235,38 @@ using std::vector; namespace { +class WarningLessThan { + public: + struct Warning { + Warning(const string& f, int ln, int cn, const string& m, int c) + : filename(f), line_num(ln), column_num(cn), message(m), count(c) { } + const string filename; + const int line_num; + const int column_num; + const string message; + const int count; + }; + + static Warning ParseWarning(const pair<string, int>& warning_and_count) { + // Lines look like file:lineno:colno: text. + const vector<string> segs = Split(warning_and_count.first, ":", 4); + CHECK_(segs.size() == 4); + return Warning(segs[0], atoi(segs[1].c_str()), atoi(segs[2].c_str()), + segs[3], warning_and_count.second); + } + + bool operator()(const pair<string, int>& a, + const pair<string, int>& b) const { + const Warning& w1 = ParseWarning(a); + const Warning& w2 = ParseWarning(b); + if (w1.filename != w2.filename) return w1.filename < w2.filename; + if (w1.line_num != w2.line_num) return w1.line_num < w2.line_num; + if (w1.column_num != w2.column_num) return w1.column_num < w2.column_num; + if (w1.message != w2.message) return w1.message < w2.message; + return w1.count < w2.count; + } +}; + string IntToString(int i) { char buf[64]; // big enough for any number snprintf(buf, sizeof(buf), "%d", i); @@ -325,8 +363,6 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> { } bool TraverseType(QualType qualtype) { - if (qualtype.isNull()) - return Base::TraverseType(qualtype); const Type* type = qualtype.getTypePtr(); if (current_ast_node_->StackContainsContent(type)) return true; // avoid recursion @@ -349,7 +385,7 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> { // system, off to the side. We don't care about qualifier // positions, so avoid the need for special-casing by just // traversing the unqualified version instead. - if (typeloc.getAs<QualifiedTypeLoc>()) { + if (isa<QualifiedTypeLoc>(typeloc)) { typeloc = typeloc.getUnqualifiedLoc(); } if (current_ast_node_->StackContainsContent(&typeloc)) @@ -613,8 +649,8 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> { return; clang::Sema& sema = compiler_->getSema(); - DeclContext::lookup_const_result ctors = sema.LookupConstructors(decl); - for (Each<NamedDecl*> it(&ctors); !it.AtEnd(); ++it) { + DeclContext::lookup_const_iterator it, end; + for (llvm::tie(it, end) = sema.LookupConstructors(decl); it != end; ++it) { // Ignore templated constructors. if (isa<FunctionTemplateDecl>(*it)) continue; @@ -686,26 +722,18 @@ class BaseAstVisitor : public RecursiveASTVisitor<Derived> { return false; } } - // Check the (single) destructor. - bool hasImplicitDeclaredDestructor = (!decl->needsImplicitDestructor() && - !decl->hasUserDeclaredDestructor()); - if (hasImplicitDeclaredDestructor) { + if (decl->hasDeclaredDestructor() && !decl->hasUserDeclaredDestructor()) { if (!TraverseImplicitDeclHelper(decl->getDestructor())) return false; } - - // Check copy and move assignment operators. - for (CXXRecordDecl::method_iterator it = decl->method_begin(); - it != decl->method_end(); ++it) { - bool isAssignmentOperator = it->isCopyAssignmentOperator() || - it->isMoveAssignmentOperator(); - if (isAssignmentOperator && it->isImplicit()) { - if (!TraverseImplicitDeclHelper(*it)) + // There can actually be two operator='s: one const and one not. + if (decl->hasDeclaredCopyAssignment() && + !decl->hasUserDeclaredCopyAssignment()) { + if (!TraverseImplicitDeclHelper(decl->getCopyAssignmentOperator(true)) || + !TraverseImplicitDeclHelper(decl->getCopyAssignmentOperator(false))) return false; - } } - return true; } @@ -1835,28 +1863,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { return true; } - // Special handling for C++ methods to detect covariant return types. - // These are defined as a derived class overriding a method with a different - // return type from the base. - bool VisitCXXMethodDecl(CXXMethodDecl* method_decl) { - if (CanIgnoreCurrentASTNode()) return true; - - if (HasCovariantReturnType(method_decl)) { - const Type* return_type = RemovePointersAndReferencesAsWritten( - method_decl->getResultType().getTypePtr()); - - VERRS(3) << "Found covariant return type in " - << method_decl->getQualifiedNameAsString() - << ", needs complete type of " - << PrintableType(return_type) - << ".\n"; - - ReportTypeUse(CurrentLoc(), return_type); - } - - return Base::VisitCXXMethodDecl(method_decl); - } - //------------------------------------------------------------ // Visitors of types derived from clang::Stmt. @@ -1907,9 +1913,6 @@ class IwyuBaseAstVisitor : public BaseAstVisitor<Derived> { case clang::CK_LValueToRValue: case clang::CK_AtomicToNonAtomic: case clang::CK_NonAtomicToAtomic: - case clang::CK_ReinterpretMemberPointer: - case clang::CK_BuiltinFnToFnPtr: - case clang::CK_ZeroToOCLEvent: // OpenCL event_t is a built-in type. break; // We shouldn't be seeing any of these kinds. @@ -3641,12 +3644,19 @@ class IwyuAstConsumer // We use an ASTFrontendAction to hook up IWYU with Clang. class IwyuAction : public ASTFrontendAction { + public: + IwyuAction(const char* executable_path) + : executable_path_(executable_path) + { + } + protected: virtual ASTConsumer* CreateASTConsumer(CompilerInstance& compiler, // NOLINT llvm::StringRef /* dummy */) { // Do this first thing after getting our hands on a CompilerInstance. InitGlobals(&compiler.getSourceManager(), - &compiler.getPreprocessor().getHeaderSearchInfo()); + &compiler.getPreprocessor().getHeaderSearchInfo(), + executable_path_); IwyuPreprocessorInfo* const preprocessor_consumer = new IwyuPreprocessorInfo(); @@ -3659,6 +3669,9 @@ class IwyuAction : public ASTFrontendAction { compiler.getPreprocessor().addCommentHandler(preprocessor_consumer); return ast_consumer; } + + private: + std::string executable_path_; }; @@ -3686,8 +3699,6 @@ int main(int argc, char **argv) { for (int i = 1; i < argc; ++i) { if (i < argc - 1 && strcmp(argv[i], "-Xiwyu") == 0) iwyu_argv[iwyu_argc++] = argv[++i]; // the word after -Xiwyu - else if (strcmp(argv[i], "--help") == 0) - iwyu_argv[iwyu_argc++] = argv[i]; // send --help straight to IWYU else clang_argv[clang_argc++] = argv[i]; } @@ -3700,11 +3711,12 @@ int main(int argc, char **argv) { clang::CompilerInstance* compiler = CreateCompilerInstance(clang_argc, clang_argv); - if (compiler != NULL) { - // Create and execute the frontend to generate an LLVM bitcode module. - llvm::OwningPtr<clang::ASTFrontendAction> action(new IwyuAction); - compiler->ExecuteAction(*action); - } + CHECK_(compiler && "Failed to process argv"); + + // Create and execute the frontend to generate an LLVM bitcode module. + llvm::OwningPtr<clang::ASTFrontendAction> action(new IwyuAction(clang_argv[0])); + if (!compiler->ExecuteAction(*action)) + return 1; llvm::llvm_shutdown(); diff --git a/iwyu_ast_util.cc b/iwyu_ast_util.cc index e3d3415..9c97749 100644 --- a/iwyu_ast_util.cc +++ b/iwyu_ast_util.cc @@ -24,7 +24,6 @@ #include "port.h" // for CHECK_ #include "llvm/Support/Casting.h" #include "llvm/Support/raw_ostream.h" -#include "clang/AST/CanonicalType.h" #include "clang/AST/Decl.h" #include "clang/AST/DeclBase.h" #include "clang/AST/DeclCXX.h" @@ -409,19 +408,14 @@ string PrintableTemplateName(const TemplateName& tpl_name) { } string PrintableTemplateArgument(const TemplateArgument& arg) { - std::string buffer; - raw_string_ostream ostream(buffer); - TemplateSpecializationType::PrintTemplateArgumentList( - ostream, &arg, 1, DefaultPrintPolicy()); - return ostream.str(); + return TemplateSpecializationType::PrintTemplateArgumentList( + &arg, 1, DefaultPrintPolicy()); } -string PrintableTemplateArgumentLoc(const TemplateArgumentLoc& arg) { - std::string buffer; - raw_string_ostream ostream(buffer); - TemplateSpecializationType::PrintTemplateArgumentList( - ostream, &arg, 1, DefaultPrintPolicy()); - return ostream.str(); +string PrintableTemplateArgumentLoc( + const TemplateArgumentLoc& arg) { + return TemplateSpecializationType::PrintTemplateArgumentList( + &arg, 1, DefaultPrintPolicy()); } // This prints to errs(). It's useful for debugging (e.g. inside gdb). @@ -535,36 +529,13 @@ bool HasImplicitConversionCtor(const CXXRecordDecl* cxx_class) { for (CXXRecordDecl::ctor_iterator ctor = cxx_class->ctor_begin(); ctor != cxx_class->ctor_end(); ++ctor) { if (ctor->isExplicit() || ctor->getNumParams() != 1 || - ctor->isCopyConstructor() || ctor->isMoveConstructor()) + ctor->isCopyConstructor()) continue; return true; } return false; } -// C++ [class.virtual]p8: -// If the return type of D::f differs from the return type of B::f, the -// class type in the return type of D::f shall be complete at the point of -// declaration of D::f or shall be the class type D. -bool HasCovariantReturnType(const CXXMethodDecl* method_decl) { - QualType derived_result_type = method_decl->getResultType(); - - for (CXXMethodDecl::method_iterator - it = method_decl->begin_overridden_methods(); - it != method_decl->end_overridden_methods(); ++it) { - // There are further constraints on covariant return types as such - // (e.g. parents must be related, derived override must have return type - // derived from base override, etc.) but the only _valid_ case I can think - // of where return type differs is when they're actually covariant. - // That is, if Clang can already compile this code without errors, and - // return types differ, it can only be due to covariance. - if ((*it)->getResultType() != derived_result_type) - return true; - } - - return false; -} - const RecordDecl* GetDefinitionForClass(const Decl* decl) { const RecordDecl* as_record = DynCastFrom(decl); const ClassTemplateDecl* as_tpl = DynCastFrom(decl); diff --git a/iwyu_ast_util.h b/iwyu_ast_util.h index db7f154..d65ecb9 100644 --- a/iwyu_ast_util.h +++ b/iwyu_ast_util.h @@ -31,7 +31,6 @@ class CXXConstructExpr; class CXXConstructorDecl; class CXXDeleteExpr; class CXXDestructorDecl; -class CXXMethodDecl; class CXXRecordDecl; class CallExpr; class CastExpr; @@ -486,10 +485,6 @@ bool IsTemplatizedFunctionDecl(const clang::FunctionDecl* decl); // conversion constructor. bool HasImplicitConversionCtor(const clang::CXXRecordDecl* cxx_class); -// Returns true if the given method is an override with covariant return type -// compared to its base. -bool HasCovariantReturnType(const clang::CXXMethodDecl* method_decl); - // If this decl is a (possibly templatized) class, return the decl // that defines the class, if present. Otherwise return NULL. const clang::RecordDecl* GetDefinitionForClass(const clang::Decl* decl); diff --git a/iwyu_driver.cc b/iwyu_driver.cc index 969789f..2226435 100644 --- a/iwyu_driver.cc +++ b/iwyu_driver.cc @@ -161,7 +161,8 @@ CompilerInstance* CreateCompilerInstance(int argc, const char **argv) { IntrusiveRefCntPtr<DiagnosticIDs> diagnostic_id(new DiagnosticIDs()); DiagnosticsEngine diagnostics(diagnostic_id, &*diagnostic_options, diagnostic_client); - Driver driver(path.str(), getDefaultTargetTriple(), "a.out", diagnostics); + Driver driver(path.str(), getDefaultTargetTriple(), "a.out", false, + diagnostics); driver.setTitle("include what you use"); // Expand out any response files passed on the command line @@ -221,7 +222,7 @@ CompilerInstance* CreateCompilerInstance(int argc, const char **argv) { compiler->setInvocation(invocation.take()); // Create the compilers actual diagnostics engine. - compiler->createDiagnostics(); + compiler->createDiagnostics(args_end - args_start, args_start); if (!compiler->hasDiagnostics()) return NULL; diff --git a/iwyu_globals.cc b/iwyu_globals.cc index 36c9408..16d20a7 100644 --- a/iwyu_globals.cc +++ b/iwyu_globals.cc @@ -50,9 +50,8 @@ static FullUseCache* function_calls_full_use_cache = NULL; static FullUseCache* class_members_full_use_cache = NULL; static void PrintHelp(const char* extra_msg) { - printf("USAGE: include-what-you-use [-Xiwyu --iwyu_opt]... <clang opts>" - " <source file>\n" - "Here are the <iwyu_opts> you can specify (e.g. -Xiwyu --verbose=3):\n" + printf("USAGE: iwyu [-Xiwyu --iwyu_opt]... <clang opts> <source file>\n" + "Here are the <opts> you can specify:\n" " --check_also=<glob>: tells iwyu to print iwyu-violation info\n" " for all files matching the given glob pattern (in addition\n" " to the default of reporting for the input .cc file and its\n" @@ -64,7 +63,6 @@ static void PrintHelp(const char* extra_msg) { " how to run iwyu under gdb for the input file, and exits.\n" " With an arg, prints only when input file matches the arg.\n" " --mapping_file=<filename>: gives iwyu a mapping file.\n" - " --no_default_mappings: do not add iwyu's default mappings.\n" " --transitive_includes_only: do not suggest that a file add\n" " foo.h unless foo.h is already visible in the file's\n" " transitive includes.\n" @@ -78,8 +76,7 @@ CommandlineFlags::CommandlineFlags() howtodebug(CommandlineFlags::kUnspecified), cwd(""), transitive_includes_only(false), - verbose(getenv("IWYU_VERBOSE") ? atoi(getenv("IWYU_VERBOSE")) : 1), - no_default_mappings(false) { + verbose(getenv("IWYU_VERBOSE") ? atoi(getenv("IWYU_VERBOSE")) : 1) { } int CommandlineFlags::ParseArgv(int argc, char** argv) { @@ -91,10 +88,9 @@ int CommandlineFlags::ParseArgv(int argc, char** argv) { {"transitive_includes_only", no_argument, NULL, 't'}, {"verbose", required_argument, NULL, 'v'}, {"mapping_file", required_argument, NULL, 'm'}, - {"no_default_mappings", no_argument, NULL, 'n'}, {0, 0, 0, 0} }; - static const char shortopts[] = "d::p:v:c:m:n"; + static const char shortopts[] = "d::p:v:c:m:"; while (true) { switch (getopt_long(argc, argv, shortopts, longopts, NULL)) { case 'c': AddGlobToReportIWYUViolationsFor(optarg); break; @@ -104,7 +100,6 @@ int CommandlineFlags::ParseArgv(int argc, char** argv) { case 't': transitive_includes_only = true; break; case 'v': verbose = atoi(optarg); break; case 'm': mapping_files.push_back(optarg); break; - case 'n': no_default_mappings = true; break; case -1: return optind; // means 'no more input' default: PrintHelp("FATAL ERROR: unknown flag."); exit(1); break; } @@ -187,14 +182,15 @@ static vector<HeaderSearchPath> ComputeHeaderSearchPaths( } void InitGlobals(clang::SourceManager* sm, - clang::HeaderSearch* header_search) { + clang::HeaderSearch* header_search, + const std::string& executable_path) { CHECK_(sm && "InitGlobals() needs a non-NULL SourceManager"); source_manager = sm; data_getter = new SourceManagerCharacterDataGetter(*source_manager); vector<HeaderSearchPath> search_paths = ComputeHeaderSearchPaths(header_search); SetHeaderSearchPaths(search_paths); - include_picker = new IncludePicker(GlobalFlags().no_default_mappings); + include_picker = new IncludePicker; function_calls_full_use_cache = new FullUseCache; class_members_full_use_cache = new FullUseCache; @@ -204,10 +200,18 @@ void InitGlobals(clang::SourceManager* sm, VERRS(6) << "Search path: " << it->path << " (" << path_type_name << ")\n"; } + // Set up mapping file search paths. + include_picker->AddMappingFileSearchPath("."); + include_picker->AddMappingFileSearchPath(GetParentPath(executable_path)); + // Add mappings. for (Each<string> it(&GlobalFlags().mapping_files); !it.AtEnd(); ++it) { include_picker->AddMappingsFromFile(*it); } + + if (GlobalFlags().mapping_files.empty()) { + include_picker->AddMappingsFromFile("iwyu.gcc.imp"); + } } const CommandlineFlags& GlobalFlags() { @@ -271,7 +275,7 @@ void InitGlobalsAndFlagsForTesting() { commandline_flags = new CommandlineFlags; source_manager = NULL; data_getter = NULL; - include_picker = new IncludePicker(GlobalFlags().no_default_mappings); + include_picker = new IncludePicker; function_calls_full_use_cache = new FullUseCache; class_members_full_use_cache = new FullUseCache; diff --git a/iwyu_globals.h b/iwyu_globals.h index a0d0fd7..36a231b 100644 --- a/iwyu_globals.h +++ b/iwyu_globals.h @@ -42,7 +42,8 @@ class SourceManagerCharacterDataGetter; int ParseIwyuCommandlineFlags(int argc, char** argv); void InitGlobals(clang::SourceManager* source_manager, - clang::HeaderSearch* header_search); + clang::HeaderSearch* header_search, + const std::string& executable_path); // Can be called by tests -- doesn't need a SourceManager or // argc/argv. Note that GlobalSourceManager() and DefaultDataGetter() @@ -75,7 +76,6 @@ struct CommandlineFlags { bool transitive_includes_only; // -t: don't add 'new' #includes to files int verbose; // -v: how much information to emit as we parse vector<string> mapping_files; // -m: mapping files - bool no_default_mappings; // -n: no default mappings }; const CommandlineFlags& GlobalFlags(); diff --git a/iwyu_include_picker.cc b/iwyu_include_picker.cc index 4789c09..b0a85b6 100644 --- a/iwyu_include_picker.cc +++ b/iwyu_include_picker.cc @@ -26,11 +26,9 @@ #include "iwyu_verrs.h" #include "port.h" // for CHECK_ -#include "llvm/ADT/OwningPtr.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/Casting.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" @@ -47,7 +45,6 @@ using std::vector; using llvm::MemoryBuffer; using llvm::OwningPtr; using llvm::SourceMgr; -using llvm::error_code; using llvm::errs; using llvm::yaml::MappingNode; using llvm::yaml::Node; @@ -58,598 +55,8 @@ using llvm::yaml::document_iterator; namespace include_what_you_use { -// If we map from A to B, it means that every time we need a -// symbol from A, we can also get it from B. Another way -// to think about it is that map_to "re-exports" all the -// symbols from map_from. -struct IncludeMapEntry { // A POD so we can make the input static - const char* map_from; // A quoted-include or a symbol name - IncludeVisibility from_visibility; - const char* map_to; // A quoted-include - IncludeVisibility to_visibility; -}; - namespace { -// Listed below are all IWYU's native symbol and include mappings, -// loosely based on GCC 4.4's libc and libstdc++. - -// Symbol -> include mappings for GNU libc -const IncludeMapEntry libc_symbol_map[] = { - { "blksize_t", kPrivate, "<sys/types.h>", kPublic }, - { "blkcnt_t", kPrivate, "<sys/stat.h>", kPublic }, - { "blkcnt_t", kPrivate, "<sys/types.h>", kPublic }, - { "blksize_t", kPrivate, "<sys/stat.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 }, - { "error_t", kPrivate, "<errno.h>", kPublic }, - { "error_t", kPrivate, "<argp.h>", kPublic }, - { "error_t", kPrivate, "<argz.h>", kPublic }, - { "fsblkcnt_t", kPrivate, "<sys/types.h>", kPublic }, - { "fsblkcnt_t", kPrivate, "<sys/statvfs.h>", kPublic }, - { "fsfilcnt_t", kPrivate, "<sys/types.h>", kPublic }, - { "fsfilcnt_t", kPrivate, "<sys/statvfs.h>", kPublic }, - { "gid_t", kPrivate, "<sys/types.h>", kPublic }, - { "gid_t", kPrivate, "<grp.h>", kPublic }, - { "gid_t", kPrivate, "<pwd.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 }, - { "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 }, - { "intptr_t", kPrivate, "<stdint.h>", kPublic }, - { "intptr_t", kPrivate, "<unistd.h>", kPublic }, - { "key_t", kPrivate, "<sys/types.h>", kPublic }, - { "key_t", kPrivate, "<sys/ipc.h>", kPublic }, - { "mode_t", kPrivate, "<sys/types.h>", kPublic }, - { "mode_t", kPrivate, "<sys/stat.h>", kPublic }, - { "mode_t", kPrivate, "<sys/ipc.h>", kPublic }, - { "mode_t", kPrivate, "<sys/mman.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, "<sys/mman.h>", kPublic }, - { "pid_t", kPrivate, "<sys/types.h>", kPublic }, - { "pid_t", kPrivate, "<unistd.h>", kPublic }, - { "pid_t", kPrivate, "<signal.h>", kPublic }, - { "pid_t", kPrivate, "<sys/msg.h>", kPublic }, - { "pid_t", kPrivate, "<sys/shm.h>", kPublic }, - { "pid_t", kPrivate, "<termios.h>", kPublic }, - { "pid_t", kPrivate, "<time.h>", kPublic }, - { "pid_t", kPrivate, "<utmpx.h>", kPublic }, - { "sigset_t", kPrivate, "<signal.h>", kPublic }, - { "sigset_t", kPrivate, "<sys/epoll.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 }, - { "ssize_t", kPrivate, "<sys/types.h>", kPublic }, - { "ssize_t", kPrivate, "<unistd.h>", kPublic }, - { "ssize_t", kPrivate, "<monetary.h>", kPublic }, - { "ssize_t", kPrivate, "<sys/msg.h>", kPublic }, - { "suseconds_t", kPrivate, "<sys/types.h>", kPublic }, - { "suseconds_t", kPrivate, "<sys/time.h>", kPublic }, - { "suseconds_t", kPrivate, "<sys/select.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 }, - { "useconds_t", kPrivate, "<sys/types.h>", kPublic }, - { "useconds_t", kPrivate, "<unistd.h>", kPublic }, - // glob.h seems to define size_t if necessary, but it should come from stddef. - { "size_t", kPrivate, "<stddef.h>", kPublic }, - // Macros that can be defined in more than one file, don't have the - // same __foo_defined guard that other types do, so the grep above - // doesn't discover them. Until I figure out a better way, I just - // add them in by hand as I discover them. - { "EOF", kPrivate, "<stdio.h>", kPublic }, - { "EOF", kPrivate, "<libio.h>", kPublic }, - { "va_list", kPrivate, "<stdarg.h>", kPublic }, - // These are symbols that could be defined in either stdlib.h or - // malloc.h, but we always want the stdlib location. - { "malloc", kPrivate, "<stdlib.h>", kPublic }, - { "calloc", kPrivate, "<stdlib.h>", kPublic }, - { "realloc", kPrivate, "<stdlib.h>", kPublic }, - { "free", kPrivate, "<stdlib.h>", kPublic }, - // Entries for NULL - { "NULL", kPrivate, "<stddef.h>", kPublic }, // 'canonical' location for NULL - { "NULL", kPrivate, "<clocale>", kPublic }, - { "NULL", kPrivate, "<cstddef>", kPublic }, - { "NULL", kPrivate, "<cstdio>", kPublic }, - { "NULL", kPrivate, "<cstdlib>", kPublic }, - { "NULL", kPrivate, "<cstring>", kPublic }, - { "NULL", kPrivate, "<ctime>", kPublic }, - { "NULL", kPrivate, "<cwchar>", kPublic }, - { "NULL", kPrivate, "<locale.h>", kPublic }, - { "NULL", kPrivate, "<stdio.h>", kPublic }, - { "NULL", kPrivate, "<stdlib.h>", kPublic }, - { "NULL", kPrivate, "<string.h>", kPublic }, - { "NULL", kPrivate, "<time.h>", kPublic }, - { "NULL", kPrivate, "<wchar.h>", kPublic }, -}; - -// Symbol -> include mappings for GNU libstdc++ -const IncludeMapEntry libstdcpp_symbol_map[] = { - // Kludge time: almost all STL types take an allocator, but they - // almost always use the default value. Usually we detect that - // and don't try to do IWYU, but sometimes it passes through. - // For instance, when adding two strings, we end up calling - // template<_CharT,_Traits,_Alloc> ... operator+( - // basic_string<_CharT,_Traits,_Alloc>, ...) - // These look like normal template args to us, so we see they're - // used and declare an iwyu dependency, even though we don't need - // to #include the traits or alloc type ourselves. The surest way - // to deal with this is to just say that everyone provides - // std::allocator. We can add more here at need. - { "std::allocator", kPrivate, "<memory>", kPublic }, - { "std::allocator", kPrivate, "<string>", kPublic }, - { "std::allocator", kPrivate, "<vector>", kPublic }, - { "std::allocator", kPrivate, "<map>", kPublic }, - { "std::allocator", kPrivate, "<set>", kPublic }, - // A similar kludge for std::char_traits. basic_string, - // basic_ostream and basic_istream have this as a default template - // argument, and sometimes it bleeds through when clang desugars the - // string/ostream/istream type. - { "std::char_traits", kPrivate, "<string>", kPublic }, - { "std::char_traits", kPrivate, "<ostream>", kPublic }, - { "std::char_traits", kPrivate, "<istream>", kPublic }, -}; - -// Private -> public include mappings for GNU libc -const IncludeMapEntry libc_include_map[] = { - // ( cd /usr/include && grep '^ *# *include' {sys/,net/,}* | perl -nle 'm/^([^:]+).*<([^>]+)>/ && print qq@ { "<$2>", kPrivate, "<$1>", kPublic },@' | grep bits/ | sort ) - // When I saw more than one mapping for these, I typically picked - // what I thought was the "best" one. - { "<bits/a.out.h>", kPrivate, "<a.out.h>", kPublic }, - { "<bits/byteswap.h>", kPrivate, "<byteswap.h>", kPublic }, - { "<bits/cmathcalls.h>", kPrivate, "<complex.h>", kPublic }, - { "<bits/confname.h>", kPrivate, "<unistd.h>", kPublic }, - { "<bits/dirent.h>", kPrivate, "<dirent.h>", kPublic }, - { "<bits/dlfcn.h>", kPrivate, "<dlfcn.h>", kPublic }, - { "<bits/elfclass.h>", kPrivate, "<link.h>", kPublic }, - { "<bits/endian.h>", kPrivate, "<endian.h>", kPublic }, - { "<bits/environments.h>", kPrivate, "<unistd.h>", kPublic }, - { "<bits/errno.h>", kPrivate, "<errno.h>", kPublic }, - { "<bits/error.h>", kPrivate, "<error.h>", kPublic }, - { "<bits/fcntl.h>", kPrivate, "<fcntl.h>", kPublic }, - { "<bits/fcntl2.h>", kPrivate, "<fcntl.h>", kPublic }, - { "<bits/fenv.h>", kPrivate, "<fenv.h>", kPublic }, - { "<bits/fenvinline.h>", kPrivate, "<fenv.h>", kPublic }, - { "<bits/huge_val.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/huge_valf.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/huge_vall.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/ioctl-types.h>", kPrivate, "<sys/ioctl.h>", kPublic }, - { "<bits/ioctls.h>", kPrivate, "<sys/ioctl.h>", kPublic }, - { "<bits/ipc.h>", kPrivate, "<sys/ipc.h>", kPublic }, - { "<bits/ipctypes.h>", kPrivate, "<sys/ipc.h>", kPublic }, - { "<bits/libio-ldbl.h>", kPrivate, "<libio.h>", kPublic }, - { "<bits/link.h>", kPrivate, "<link.h>", kPublic }, - { "<bits/locale.h>", kPrivate, "<locale.h>", kPublic }, - { "<bits/mathcalls.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/mathdef.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/mman.h>", kPrivate, "<sys/mman.h>", kPublic }, - { "<bits/monetary-ldbl.h>", kPrivate, "<monetary.h>", kPublic }, - { "<bits/mqueue.h>", kPrivate, "<mqueue.h>", kPublic }, - { "<bits/mqueue2.h>", kPrivate, "<mqueue.h>", kPublic }, - { "<bits/msq.h>", kPrivate, "<sys/msg.h>", kPublic }, - { "<bits/nan.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/netdb.h>", kPrivate, "<netdb.h>", kPublic }, - { "<bits/poll.h>", kPrivate, "<sys/poll.h>", kPrivate }, - { "<bits/posix1_lim.h>", kPrivate, "<limits.h>", kPublic }, - { "<bits/posix2_lim.h>", kPrivate, "<limits.h>", kPublic }, - { "<bits/posix_opt.h>", kPrivate, "<unistd.h>", kPublic }, - { "<bits/printf-ldbl.h>", kPrivate, "<printf.h>", kPublic }, - { "<bits/pthreadtypes.h>", kPrivate, "<pthread.h>", kPublic }, - { "<bits/resource.h>", kPrivate, "<sys/resource.h>", kPublic }, - { "<bits/sched.h>", kPrivate, "<sched.h>", kPublic }, - { "<bits/select.h>", kPrivate, "<sys/select.h>", kPublic }, - { "<bits/sem.h>", kPrivate, "<sys/sem.h>", kPublic }, - { "<bits/semaphore.h>", kPrivate, "<semaphore.h>", kPublic }, - { "<bits/setjmp.h>", kPrivate, "<setjmp.h>", kPublic }, - { "<bits/shm.h>", kPrivate, "<sys/shm.h>", kPublic }, - { "<bits/sigaction.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/sigcontext.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/siginfo.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/signum.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/sigset.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/sigstack.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/sigthread.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/sockaddr.h>", kPrivate, "<sys/un.h>", kPublic }, - { "<bits/socket.h>", kPrivate, "<sys/socket.h>", kPublic }, - { "<bits/stab.def>", kPrivate, "<stab.h>", kPublic }, - { "<bits/stat.h>", kPrivate, "<sys/stat.h>", kPublic }, - { "<bits/statfs.h>", kPrivate, "<sys/statfs.h>", kPublic }, - { "<bits/statvfs.h>", kPrivate, "<sys/statvfs.h>", kPublic }, - { "<bits/stdio-ldbl.h>", kPrivate, "<stdio.h>", kPublic }, - { "<bits/stdio-lock.h>", kPrivate, "<libio.h>", kPublic }, - { "<bits/stdio.h>", kPrivate, "<stdio.h>", kPublic }, - { "<bits/stdio2.h>", kPrivate, "<stdio.h>", kPublic }, - { "<bits/stdio_lim.h>", kPrivate, "<stdio.h>", kPublic }, - { "<bits/stdlib-ldbl.h>", kPrivate, "<stdlib.h>", kPublic }, - { "<bits/stdlib.h>", kPrivate, "<stdlib.h>", kPublic }, - { "<bits/string.h>", kPrivate, "<string.h>", kPublic }, - { "<bits/string2.h>", kPrivate, "<string.h>", kPublic }, - { "<bits/string3.h>", kPrivate, "<string.h>", kPublic }, - { "<bits/stropts.h>", kPrivate, "<stropts.h>", kPublic }, - { "<bits/sys_errlist.h>", kPrivate, "<stdio.h>", kPublic }, - { "<bits/syscall.h>", kPrivate, "<sys/syscall.h>", kPrivate }, - { "<bits/syslog-ldbl.h>", kPrivate, "<sys/syslog.h>", kPrivate }, - { "<bits/syslog-path.h>", kPrivate, "<sys/syslog.h>", kPrivate }, - { "<bits/syslog.h>", kPrivate, "<sys/syslog.h>", kPrivate }, - { "<bits/termios.h>", kPrivate, "<termios.h>", kPublic }, - { "<bits/time.h>", kPrivate, "<sys/time.h>", kPublic }, - { "<bits/types.h>", kPrivate, "<sys/types.h>", kPublic }, - { "<bits/uio.h>", kPrivate, "<sys/uio.h>", kPublic }, - { "<bits/unistd.h>", kPrivate, "<unistd.h>", kPublic }, - { "<bits/ustat.h>", kPrivate, "<sys/ustat.h>", kPrivate }, - { "<bits/utmp.h>", kPrivate, "<utmp.h>", kPublic }, - { "<bits/utmpx.h>", kPrivate, "<utmpx.h>", kPublic }, - { "<bits/utsname.h>", kPrivate, "<sys/utsname.h>", kPublic }, - { "<bits/waitflags.h>", kPrivate, "<sys/wait.h>", kPublic }, - { "<bits/waitstatus.h>", kPrivate, "<sys/wait.h>", kPublic }, - { "<bits/wchar-ldbl.h>", kPrivate, "<wchar.h>", kPublic }, - { "<bits/wchar.h>", kPrivate, "<wchar.h>", kPublic }, - { "<bits/wchar2.h>", kPrivate, "<wchar.h>", kPublic }, - { "<bits/xopen_lim.h>", kPrivate, "<limits.h>", kPublic }, - { "<bits/xtitypes.h>", kPrivate, "<stropts.h>", kPublic }, - // Sometimes libc tells you what mapping to do via an '#error': - // # error "Never use <bits/dlfcn.h> directly; include <dlfcn.h> instead." - // ( cd /usr/include && grep -R '^ *# *error "Never use' * | perl -nle 'm/<([^>]+).*<([^>]+)/ && print qq@ { "<$1>", kPrivate, "<$2>", kPublic },@' | sort ) - { "<bits/a.out.h>", kPrivate, "<a.out.h>", kPublic }, - { "<bits/byteswap.h>", kPrivate, "<byteswap.h>", kPublic }, - { "<bits/cmathcalls.h>", kPrivate, "<complex.h>", kPublic }, - { "<bits/confname.h>", kPrivate, "<unistd.h>", kPublic }, - { "<bits/dirent.h>", kPrivate, "<dirent.h>", kPublic }, - { "<bits/dlfcn.h>", kPrivate, "<dlfcn.h>", kPublic }, - { "<bits/elfclass.h>", kPrivate, "<link.h>", kPublic }, - { "<bits/endian.h>", kPrivate, "<endian.h>", kPublic }, - { "<bits/fcntl.h>", kPrivate, "<fcntl.h>", kPublic }, - { "<bits/fenv.h>", kPrivate, "<fenv.h>", kPublic }, - { "<bits/huge_val.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/huge_valf.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/huge_vall.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/in.h>", kPrivate, "<netinet/in.h>", kPublic }, - { "<bits/inf.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/ioctl-types.h>", kPrivate, "<sys/ioctl.h>", kPublic }, - { "<bits/ioctls.h>", kPrivate, "<sys/ioctl.h>", kPublic }, - { "<bits/ipc.h>", kPrivate, "<sys/ipc.h>", kPublic }, - { "<bits/locale.h>", kPrivate, "<locale.h>", kPublic }, - { "<bits/mathdef.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/mathinline.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/mman.h>", kPrivate, "<sys/mman.h>", kPublic }, - { "<bits/mqueue.h>", kPrivate, "<mqueue.h>", kPublic }, - { "<bits/msq.h>", kPrivate, "<sys/msg.h>", kPublic }, - { "<bits/nan.h>", kPrivate, "<math.h>", kPublic }, - { "<bits/poll.h>", kPrivate, "<sys/poll.h>", kPrivate }, - { "<bits/predefs.h>", kPrivate, "<features.h>", kPublic }, - { "<bits/resource.h>", kPrivate, "<sys/resource.h>", kPublic }, - { "<bits/select.h>", kPrivate, "<sys/select.h>", kPublic }, - { "<bits/semaphore.h>", kPrivate, "<semaphore.h>", kPublic }, - { "<bits/sigcontext.h>", kPrivate, "<signal.h>", kPublic }, - { "<bits/string.h>", kPrivate, "<string.h>", kPublic }, - { "<bits/string2.h>", kPrivate, "<string.h>", kPublic }, - { "<bits/string3.h>", kPrivate, "<string.h>", kPublic }, - { "<bits/syscall.h>", kPrivate, "<sys/syscall.h>", kPrivate }, - // Top-level #includes that just forward to another file: - // $ for i in /usr/include/*; do [ -f $i ] && [ `wc -l < $i` = 1 ] && echo $i; done - // (poll.h, syscall.h, syslog.h, ustat.h, wait.h). - // For each file, I looked at the list of canonical header files -- - // http://www.opengroup.org/onlinepubs/9699919799/idx/head.html -- - // to decide which of the two files is canonical. If neither is - // on the POSIX.1 1998 list, I just choose the top-level one. - { "<sys/poll.h>", kPrivate, "<poll.h>", kPublic }, - { "<sys/syscall.h>", kPrivate, "<syscall.h>", kPublic }, - { "<sys/syslog.h>", kPrivate, "<syslog.h>", kPublic }, - { "<sys/ustat.h>", kPrivate, "<ustat.h>", kPublic }, - { "<wait.h>", kPrivate, "<sys/wait.h>", kPublic }, - // These are all files in bits/ that delegate to asm/ and linux/ to - // do all (or lots) of the work. Note these are private->private. - // $ for i in /usr/include/bits/*; do for dir in asm linux; do grep -H -e $dir/`basename $i` $i; done; done - { "<linux/errno.h>", kPrivate, "<bits/errno.h>", kPrivate }, - { "<asm/ioctls.h>", kPrivate, "<bits/ioctls.h>", kPrivate }, - { "<asm/socket.h>", kPrivate, "<bits/socket.h>", kPrivate }, - { "<linux/socket.h>", kPrivate, "<bits/socket.h>", kPrivate }, - // Some asm files have 32- and 64-bit variants: - // $ ls /usr/include/asm/*_{32,64}.h - { "<asm/posix_types_32.h>", kPrivate, "<asm/posix_types.h>", kPublic }, - { "<asm/posix_types_64.h>", kPrivate, "<asm/posix_types.h>", kPublic }, - { "<asm/unistd_32.h>", kPrivate, "<asm/unistd.h>", kPrivate }, - { "<asm/unistd_64.h>", kPrivate, "<asm/unistd.h>", kPrivate }, - // I don't know what grep would have found these. I found them - // via user report. - { "<asm/errno.h>", kPrivate, "<errno.h>", kPublic }, - { "<asm/errno-base.h>", kPrivate, "<errno.h>", kPublic }, - { "<asm/ptrace-abi.h>", kPrivate, "<asm/ptrace.h>", kPublic }, - { "<asm/unistd.h>", kPrivate, "<syscall.h>", kPublic }, - { "<linux/limits.h>", kPrivate, "<limits.h>", kPublic }, // PATH_MAX - { "<linux/prctl.h>", kPrivate, "<sys/prctl.h>", kPublic }, - { "<sys/ucontext.h>", kPrivate, "<ucontext.h>", kPublic }, - // Allow the C++ wrappers around C files. Without these mappings, - // if you #include <cstdio>, iwyu will tell you to replace it with - // <stdio.h>, which is where the symbols are actually defined. We - // inhibit that behavior to keep the <cstdio> alone. Note this is a - // public-to-public mapping: we don't want to *replace* <assert.h> - // with <cassert>, we just want to avoid suggesting changing - // <cassert> back to <assert.h>. (If you *did* want to replace - // assert.h with cassert, you'd change it to a public->private - // mapping.) Here is how I identified the files to map: - // $ for i in /usr/include/c++/4.4/c* ; do ls /usr/include/`basename $i | cut -b2-`.h /usr/lib/gcc/*/4.4/include/`basename $i | cut -b2-`.h 2>/dev/null ; done - { "<assert.h>", kPublic, "<cassert>", kPublic }, - { "<complex.h>", kPublic, "<ccomplex>", kPublic }, - { "<ctype.h>", kPublic, "<cctype>", kPublic }, - { "<errno.h>", kPublic, "<cerrno>", kPublic }, - { "<fenv.h>", kPublic, "<cfenv>", kPublic }, - { "<float.h>", kPublic, "<cfloat>", kPublic }, - { "<inttypes.h>", kPublic, "<cinttypes>", kPublic }, - { "<iso646.h>", kPublic, "<ciso646>", kPublic }, - { "<limits.h>", kPublic, "<climits>", kPublic }, - { "<locale.h>", kPublic, "<clocale>", kPublic }, - { "<math.h>", kPublic, "<cmath>", kPublic }, - { "<setjmp.h>", kPublic, "<csetjmp>", kPublic }, - { "<signal.h>", kPublic, "<csignal>", kPublic }, - { "<stdarg.h>", kPublic, "<cstdarg>", kPublic }, - { "<stdbool.h>", kPublic, "<cstdbool>", kPublic }, - { "<stddef.h>", kPublic, "<cstddef>", kPublic }, - { "<stdint.h>", kPublic, "<cstdint>", kPublic }, - { "<stdio.h>", kPublic, "<cstdio>", kPublic }, - { "<stdlib.h>", kPublic, "<cstdlib>", kPublic }, - { "<string.h>", kPublic, "<cstring>", kPublic }, - { "<tgmath.h>", kPublic, "<ctgmath>", kPublic }, - { "<time.h>", kPublic, "<ctime>", kPublic }, - { "<wchar.h>", kPublic, "<cwchar>", kPublic }, - { "<wctype.h>", kPublic, "<cwctype>", kPublic }, -}; - -// Private -> public include mappings for GNU libstdc++ -const IncludeMapEntry libstdcpp_include_map[] = { - // ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && grep '^ *# *include' {ext/,tr1/,}* | perl -nle 'm/^([^:]+).*<([^>]+)>/ && print qq@ { "<$2>", kPrivate, "<$1>", kPublic },@' | grep -e bits/ -e tr1_impl/ | sort -u) - // I removed a lot of 'meaningless' dependencies -- for instance, - // <functional> #includes <bits/stringfwd.h>, but if someone is - // using strings, <functional> isn't enough to satisfy iwyu. - // We may need to add other dirs in future versions of gcc. - { "<bits/algorithmfwd.h>", kPrivate, "<algorithm>", kPublic }, - { "<bits/allocator.h>", kPrivate, "<memory>", kPublic }, - { "<bits/atomic_word.h>", kPrivate, "<ext/atomicity.h>", kPublic }, - { "<bits/basic_file.h>", kPrivate, "<fstream>", kPublic }, - { "<bits/basic_ios.h>", kPrivate, "<ios>", kPublic }, - { "<bits/basic_string.h>", kPrivate, "<string>", kPublic }, - { "<bits/basic_string.tcc>", kPrivate, "<string>", kPublic }, - { "<bits/boost_sp_shared_count.h>", kPrivate, "<memory>", kPublic }, - { "<bits/c++io.h>", kPrivate, "<ext/stdio_sync_filebuf.h>", kPublic }, - { "<bits/c++config.h>", kPrivate, "<cstddef>", kPublic }, - { "<bits/char_traits.h>", kPrivate, "<string>", kPublic }, - { "<bits/cmath.tcc>", kPrivate, "<cmath>", kPublic }, - { "<bits/codecvt.h>", kPrivate, "<fstream>", kPublic }, - { "<bits/cxxabi_tweaks.h>", kPrivate, "<cxxabi.h>", kPublic }, - { "<bits/deque.tcc>", kPrivate, "<deque>", kPublic }, - { "<bits/fstream.tcc>", kPrivate, "<fstream>", kPublic }, - { "<bits/functional_hash.h>", kPrivate, "<unordered_map>", kPublic }, - { "<bits/gslice.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/gslice_array.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/hashtable.h>", kPrivate, "<unordered_map>", kPublic }, - { "<bits/hashtable.h>", kPrivate, "<unordered_set>", kPublic }, - { "<bits/indirect_array.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/ios_base.h>", kPrivate, "<iostream>", kPublic }, - { "<bits/ios_base.h>", kPrivate, "<ios>", kPublic }, - { "<bits/ios_base.h>", kPrivate, "<iomanip>", kPublic }, - { "<bits/locale_classes.h>", kPrivate, "<locale>", kPublic }, - { "<bits/locale_facets.h>", kPrivate, "<locale>", kPublic }, - { "<bits/locale_facets_nonio.h>", kPrivate, "<locale>", kPublic }, - { "<bits/localefwd.h>", kPrivate, "<locale>", kPublic }, - { "<bits/mask_array.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/ostream.tcc>", kPrivate, "<ostream>", kPublic }, - { "<bits/ostream_insert.h>", kPrivate, "<ostream>", kPublic }, - { "<bits/postypes.h>", kPrivate, "<iostream>", kPublic }, - { "<bits/slice_array.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/stl_algo.h>", kPrivate, "<algorithm>", kPublic }, - { "<bits/stl_algobase.h>", kPrivate, "<algorithm>", kPublic }, - { "<bits/stl_bvector.h>", kPrivate, "<vector>", kPublic }, - { "<bits/stl_construct.h>", kPrivate, "<memory>", kPublic }, - { "<bits/stl_deque.h>", kPrivate, "<deque>", kPublic }, - { "<bits/stl_function.h>", kPrivate, "<functional>", kPublic }, - { "<bits/stl_heap.h>", kPrivate, "<queue>", kPublic }, - { "<bits/stl_iterator.h>", kPrivate, "<iterator>", kPublic }, - { "<bits/stl_iterator_base_funcs.h>", kPrivate, "<iterator>", kPublic }, - { "<bits/stl_iterator_base_types.h>", kPrivate, "<iterator>", kPublic }, - { "<bits/stl_list.h>", kPrivate, "<list>", kPublic }, - { "<bits/stl_map.h>", kPrivate, "<map>", kPublic }, - { "<bits/stl_multimap.h>", kPrivate, "<map>", kPublic }, - { "<bits/stl_multiset.h>", kPrivate, "<set>", kPublic }, - { "<bits/stl_numeric.h>", kPrivate, "<numeric>", kPublic }, - { "<bits/stl_pair.h>", kPrivate, "<utility>", kPublic }, - { "<bits/stl_pair.h>", kPrivate, "<tr1/utility>", kPublic }, - { "<bits/stl_queue.h>", kPrivate, "<queue>", kPublic }, - { "<bits/stl_raw_storage_iter.h>", kPrivate, "<memory>", kPublic }, - { "<bits/stl_relops.h>", kPrivate, "<utility>", kPublic }, - { "<bits/stl_set.h>", kPrivate, "<set>", kPublic }, - { "<bits/stl_stack.h>", kPrivate, "<stack>", kPublic }, - { "<bits/stl_tempbuf.h>", kPrivate, "<memory>", kPublic }, - { "<bits/stl_tree.h>", kPrivate, "<map>", kPublic }, - { "<bits/stl_tree.h>", kPrivate, "<set>", kPublic }, - { "<bits/stl_uninitialized.h>", kPrivate, "<memory>", kPublic }, - { "<bits/stl_vector.h>", kPrivate, "<vector>", kPublic }, - { "<bits/stream_iterator.h>", kPrivate, "<iterator>", kPublic }, - { "<bits/streambuf.tcc>", kPrivate, "<streambuf>", kPublic }, - { "<bits/streambuf_iterator.h>", kPrivate, "<iterator>", kPublic }, - { "<bits/stringfwd.h>", kPrivate, "<string>", kPublic }, - { "<bits/valarray_after.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/valarray_array.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/valarray_before.h>", kPrivate, "<valarray>", kPublic }, - { "<bits/vector.tcc>", kPrivate, "<vector>", kPublic }, - { "<tr1_impl/array>", kPrivate, "<array>", kPublic }, - { "<tr1_impl/array>", kPrivate, "<tr1/array>", kPublic }, - { "<tr1_impl/boost_shared_ptr.h>", kPrivate, "<memory>", kPublic }, - { "<tr1_impl/boost_shared_ptr.h>", kPrivate, "<tr1/memory>", kPublic }, - { "<tr1_impl/boost_sp_counted_base.h>", kPrivate, "<memory>", kPublic }, - { "<tr1_impl/boost_sp_counted_base.h>", kPrivate, "<tr1/memory>", kPublic }, - { "<tr1_impl/cctype>", kPrivate, "<cctype>", kPublic }, - { "<tr1_impl/cctype>", kPrivate, "<tr1/cctype>", kPublic }, - { "<tr1_impl/cfenv>", kPrivate, "<cfenv>", kPublic }, - { "<tr1_impl/cfenv>", kPrivate, "<tr1/cfenv>", kPublic }, - { "<tr1_impl/cinttypes>", kPrivate, "<cinttypes>", kPublic }, - { "<tr1_impl/cinttypes>", kPrivate, "<tr1/cinttypes>", kPublic }, - { "<tr1_impl/cmath>", kPrivate, "<cmath>", kPublic }, - { "<tr1_impl/cmath>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1_impl/complex>", kPrivate, "<complex>", kPublic }, - { "<tr1_impl/complex>", kPrivate, "<tr1/complex>", kPublic }, - { "<tr1_impl/cstdint>", kPrivate, "<cstdint>", kPublic }, - { "<tr1_impl/cstdint>", kPrivate, "<tr1/cstdint>", kPublic }, - { "<tr1_impl/cstdio>", kPrivate, "<cstdio>", kPublic }, - { "<tr1_impl/cstdio>", kPrivate, "<tr1/cstdio>", kPublic }, - { "<tr1_impl/cstdlib>", kPrivate, "<cstdlib>", kPublic }, - { "<tr1_impl/cstdlib>", kPrivate, "<tr1/cstdlib>", kPublic }, - { "<tr1_impl/cwchar>", kPrivate, "<cwchar>", kPublic }, - { "<tr1_impl/cwchar>", kPrivate, "<tr1/cwchar>", kPublic }, - { "<tr1_impl/cwctype>", kPrivate, "<cwctype>", kPublic }, - { "<tr1_impl/cwctype>", kPrivate, "<tr1/cwctype>", kPublic }, - { "<tr1_impl/functional>", kPrivate, "<functional>", kPublic }, - { "<tr1_impl/functional>", kPrivate, "<tr1/functional>", kPublic }, - { "<tr1_impl/random>", kPrivate, "<random>", kPublic }, - { "<tr1_impl/random>", kPrivate, "<tr1/random>", kPublic }, - { "<tr1_impl/regex>", kPrivate, "<regex>", kPublic }, - { "<tr1_impl/regex>", kPrivate, "<tr1/regex>", kPublic }, - { "<tr1_impl/type_traits>", kPrivate, "<tr1/type_traits>", kPublic }, - { "<tr1_impl/type_traits>", kPrivate, "<type_traits>", kPublic }, - { "<tr1_impl/unordered_map>", kPrivate, "<tr1/unordered_map>", kPublic }, - { "<tr1_impl/unordered_map>", kPrivate, "<unordered_map>", kPublic }, - { "<tr1_impl/unordered_set>", kPrivate, "<tr1/unordered_set>", kPublic }, - { "<tr1_impl/unordered_set>", kPrivate, "<unordered_set>", kPublic }, - { "<tr1_impl/utility>", kPrivate, "<tr1/utility>", kPublic }, - { "<tr1_impl/utility>", kPrivate, "<utility>", kPublic }, - // This didn't come from the grep, but seems to be where swap() - // is defined? - { "<bits/move.h>", kPrivate, "<algorithm>", kPublic }, // for swap<>() - // Hash and hashtable-based containers. - { "<tr1_impl/functional_hash.h>", kPrivate, "<tr1/functional>", kPublic }, - { "<tr1_impl/functional_hash.h>", kPrivate, "<tr1/unordered_map>", kPublic }, - { "<tr1_impl/functional_hash.h>", kPrivate, "<tr1/unordered_set>", kPublic }, - { "<tr1/functional_hash.h>", kPrivate, "<tr1/functional>", kPublic }, - { "<tr1/functional_hash.h>", kPrivate, "<tr1/unordered_map>", kPublic }, - { "<tr1/functional_hash.h>", kPrivate, "<tr1/unordered_set>", kPublic }, - { "<tr1_impl/hashtable>", kPrivate, "<tr1/unordered_map>", kPublic }, - { "<tr1_impl/hashtable>", kPrivate, "<tr1/unordered_set>", kPublic }, - { "<tr1/hashtable.h>", kPrivate, "<tr1/unordered_map>", kPublic }, - { "<tr1/hashtable.h>", kPrivate, "<tr1/unordered_set>", kPublic }, - // All .tcc files are gcc internal-include files. We get them from - // ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && grep -R '^ *# *include.*tcc' * | perl -nle 'm/^([^:]+).*[<"]([^>"]+)[>"]/ && print qq@ { "<$2>", kPrivate, "<$1>", kPublic },@' | sort ) - // I had to manually edit some of the entries to say the map-to is private. - { "<bits/basic_ios.tcc>", kPrivate, "<bits/basic_ios.h>", kPrivate }, - { "<bits/basic_string.tcc>", kPrivate, "<string>", kPublic }, - { "<bits/cmath.tcc>", kPrivate, "<cmath>", kPublic }, - { "<bits/deque.tcc>", kPrivate, "<deque>", kPublic }, - { "<bits/fstream.tcc>", kPrivate, "<fstream>", kPublic }, - { "<bits/istream.tcc>", kPrivate, "<istream>", kPublic }, - { "<bits/list.tcc>", kPrivate, "<list>", kPublic }, - { "<bits/locale_classes.tcc>", kPrivate, - "<bits/locale_classes.h>", kPrivate }, - { "<bits/locale_facets.tcc>", kPrivate, "<bits/locale_facets.h>", kPrivate }, - { "<bits/locale_facets_nonio.tcc>", kPrivate, - "<bits/locale_facets_nonio.h>", kPrivate }, - { "<bits/ostream.tcc>", kPrivate, "<ostream>", kPublic }, - { "<bits/sstream.tcc>", kPrivate, "<sstream>", kPublic }, - { "<bits/streambuf.tcc>", kPrivate, "<streambuf>", kPublic }, - { "<bits/valarray_array.tcc>", kPrivate, - "<bits/valarray_array.h>", kPrivate }, - { "<bits/vector.tcc>", kPrivate, "<vector>", kPublic }, - { "<debug/safe_iterator.tcc>", kPrivate, "<debug/safe_iterator.h>", kPublic }, - { "<tr1/bessel_function.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/beta_function.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/ell_integral.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/exp_integral.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/gamma.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/hypergeometric.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/legendre_function.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/modified_bessel_func.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/poly_hermite.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/poly_laguerre.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1/riemann_zeta.tcc>", kPrivate, "<tr1/cmath>", kPublic }, - { "<tr1_impl/random.tcc>", kPrivate, "<tr1_impl/random>", kPrivate }, - // Some bits->bits #includes: A few files in bits re-export - // symbols from other files in bits. - // ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && grep '^ *# *include.*bits/' bits/* | perl -nle 'm/^([^:]+).*<([^>]+)>/ && print qq@ { "<$2>", kPrivate, "<$1>", kPrivate },@' | grep bits/ | sort -u) - // and carefully picked reasonable-looking results (algorithm - // *uses* pair but doesn't *re-export* pair, for instance). - { "<bits/boost_concept_check.h>", kPrivate, - "<bits/concept_check.h>", kPrivate }, - { "<bits/c++allocator.h>", kPrivate, "<bits/allocator.h>", kPrivate }, - { "<bits/codecvt.h>", kPrivate, "<bits/locale_facets_nonio.h>", kPrivate }, - { "<bits/ctype_base.h>", kPrivate, "<bits/locale_facets.h>", kPrivate }, - { "<bits/ctype_inline.h>", kPrivate, "<bits/locale_facets.h>", kPrivate }, - { "<bits/functexcept.h>", kPrivate, "<bits/stl_algobase.h>", kPrivate }, - { "<bits/locale_classes.h>", kPrivate, "<bits/basic_ios.h>", kPrivate }, - { "<bits/locale_facets.h>", kPrivate, "<bits/basic_ios.h>", kPrivate }, - { "<bits/messages_members.h>", kPrivate, - "<bits/locale_facets_nonio.h>", kPrivate }, - { "<bits/postypes.h>", kPrivate, "<bits/char_traits.h>", kPrivate }, - { "<bits/slice_array.h>", kPrivate, "<bits/valarray_before.h>", kPrivate }, - { "<bits/stl_construct.h>", kPrivate, "<bits/stl_tempbuf.h>", kPrivate }, - { "<bits/stl_move.h>", kPrivate, "<bits/stl_algobase.h>", kPrivate }, - { "<bits/stl_uninitialized.h>", kPrivate, "<bits/stl_tempbuf.h>", kPrivate }, - { "<bits/stl_vector.h>", kPrivate, "<bits/stl_bvector.h>", kPrivate }, - { "<bits/streambuf_iterator.h>", kPrivate, "<bits/basic_ios.h>", kPrivate }, - // I don't think we want to be having people move to 'backward/' - // yet. (These hold deprecated STL classes that we still use - // actively.) These are the ones that turned up in an analysis of - { "<backward/auto_ptr.h>", kPrivate, "<memory>", kPublic }, - { "<backward/binders.h>", kPrivate, "<functional>", kPublic }, - { "<backward/hash_fun.h>", kPrivate, "<hash_map>", kPublic }, - { "<backward/hash_fun.h>", kPrivate, "<hash_set>", kPublic }, - { "<backward/hashtable.h>", kPrivate, "<hash_map>", kPublic }, - { "<backward/hashtable.h>", kPrivate, "<hash_set>", kPublic }, - { "<backward/strstream>", kPrivate, "<strstream>", kPublic }, - // We have backward as part of the -I search path now, so have the - // non-backwards-prefix version as well. - { "<auto_ptr.h>", kPrivate, "<memory>", kPublic }, - { "<binders.h>", kPrivate, "<functional>", kPublic }, - { "<hash_fun.h>", kPrivate, "<hash_map>", kPublic }, - { "<hash_fun.h>", kPrivate, "<hash_set>", kPublic }, - { "<hashtable.h>", kPrivate, "<hash_map>", kPublic }, - { "<hashtable.h>", kPrivate, "<hash_set>", kPublic }, - // (This one should perhaps be found automatically somehow.) - { "<ext/sso_string_base.h>", kPrivate, "<string>", kPublic }, - // The iostream .h files are confusing. Lots of private headers, - // which are handled above, but we also have public headers - // #including each other (eg <iostream> #includes <istream>). We - // are pretty forgiving: if a user specifies any public header, we - // generally don't require the others. - // ( cd /usr/crosstool/v12/gcc-4.3.1-glibc-2.3.6-grte/x86_64-unknown-linux-gnu/x86_64-unknown-linux-gnu/include/c++/4.3.1 && egrep '^ *# *include <(istream|ostream|iostream|fstream|sstream|streambuf|ios|iosfwd)>' *stream* ios | perl -nle 'm/^([^:]+).*[<"]([^>"]+)[>"]/ and print qq@ { "<$2>", kPublic, "<$1>", kPublic },@' | sort -u ) - { "<ios>", kPublic, "<istream>", kPublic }, - { "<ios>", kPublic, "<ostream>", kPublic }, - { "<iosfwd>", kPublic, "<ios>", kPublic }, - { "<iosfwd>", kPublic, "<streambuf>", kPublic }, - { "<istream>", kPublic, "<fstream>", kPublic }, - { "<istream>", kPublic, "<iostream>", kPublic }, - { "<istream>", kPublic, "<sstream>", kPublic }, - { "<ostream>", kPublic, "<fstream>", kPublic }, - { "<ostream>", kPublic, "<iostream>", kPublic }, - { "<ostream>", kPublic, "<istream>", kPublic }, - { "<ostream>", kPublic, "<sstream>", kPublic }, - { "<streambuf>", kPublic, "<ios>", kPublic }, - // The location of exception_defines.h varies by GCC version. It should - // never be included directly. - { "<bits/exception_defines.h>", kPrivate, "<exception>", kPublic }, - { "<exception_defines.h>", kPrivate, "<exception>", kPublic }, -}; - // Returns true if str is a valid quoted filepath pattern (i.e. either // a quoted filepath or "@" followed by a regex for matching a quoted // filepath). @@ -779,76 +186,36 @@ vector<string> GetSequenceValue(Node* node) { return result; } -// If new_path doesn't already exist in search_path, makes a copy of search_path -// and adds new_path to it. -// Returns the original or extended search path. -vector<string> ExtendMappingFileSearchPath(const vector<string>& search_path, - const string& new_path) { - CHECK_(IsAbsolutePath(new_path)); - - if (std::find(search_path.begin(), - search_path.end(), - new_path) == search_path.end()) { - vector<string> extended(search_path); - extended.push_back(new_path); - return extended; - } +// Build a diagnostic string for an error in a mapping file. +// TODO(kimgr): Try to fix YAML parser to be able to use proper diagnostic +// infrastructure, for colored output, etc. +string MappingDiag(const SourceMgr& source_manager, + const string& filename, const Node& node, const char* message) { + pair<unsigned, unsigned> printable_loc + = source_manager.getLineAndColumn(node.getSourceRange().Start); - return search_path; -} + string buf; + llvm::raw_string_ostream os(buf); + os << filename << ":" + << printable_loc.first << ":" << printable_loc.second << ": " + << message; -// Scans search_path for existing files with filename. -// If filename is absolute and exists, return it. -// If filename is relative and exists based on cwd, return it in absolute form. -// If filename is relative and doesn't exist, try to find it along search_path. -// Returns an absolute filename if file is found, otherwise filename untouched. -string FindFileInSearchPath(const vector<string>& search_path, - const string& filename) { - if (llvm::sys::fs::exists(filename)) { - // If the file exists, no matter if its path is relative or absolute, - // return it in absolute form. - return MakeAbsolutePath(filename); - } else if (!IsAbsolutePath(filename)) { - // If it's relative, scan search path. - for (Each<string> it(&search_path); !it.AtEnd(); ++it) { - string candidate = MakeAbsolutePath(*it, filename); - if (llvm::sys::fs::exists(candidate)) { - return candidate; - } - } - } - - // This is proven not to exist, so handle the error when - // we attempt to open it. - return filename; + return os.str(); } } // namespace -IncludePicker::IncludePicker(bool no_default_mappings) +IncludePicker::IncludePicker() : symbol_include_map_(), filepath_include_map_(), filepath_visibility_map_(), quoted_includes_to_quoted_includers_(), has_called_finalize_added_include_lines_(false) { - if (!no_default_mappings) { - AddDefaultMappings(); - } -} - -void IncludePicker::AddDefaultMappings() { - AddSymbolMappings(libc_symbol_map, IWYU_ARRAYSIZE(libc_symbol_map)); - AddSymbolMappings(libstdcpp_symbol_map, IWYU_ARRAYSIZE(libstdcpp_symbol_map)); - - AddIncludeMappings(libc_include_map, - IWYU_ARRAYSIZE(libc_include_map)); - AddIncludeMappings(libstdcpp_include_map, - IWYU_ARRAYSIZE(libstdcpp_include_map)); } void IncludePicker::MarkVisibility( const string& quoted_filepath_pattern, - IncludeVisibility vis) { + IncludePicker::Visibility vis) { CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore"); // insert() leaves any old value alone, and only inserts if the key is new. @@ -911,6 +278,16 @@ void IncludePicker::AddDirectInclude(const string& includer_filepath, } } +void IncludePicker::AddMappingFileSearchPath(const string& path) { + string absolute_path = MakeAbsolutePath(path); + if (std::find(mapping_file_search_path_.begin(), + mapping_file_search_path_.end(), + absolute_path) == mapping_file_search_path_.end()) { + VERRS(6) << "Adding mapping file search path: " << absolute_path << "\n"; + mapping_file_search_path_.push_back(absolute_path); + } +} + void IncludePicker::AddMapping(const string& map_from, const string& map_to) { VERRS(4) << "Adding mapping from " << map_from << " to " << map_to << "\n"; CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore"); @@ -921,17 +298,18 @@ void IncludePicker::AddMapping(const string& map_from, const string& map_to) { } void IncludePicker::AddIncludeMapping(const string& map_from, - IncludeVisibility from_visibility, + IncludePicker::Visibility from_visibility, const string& map_to, - IncludeVisibility to_visibility) { + IncludePicker::Visibility to_visibility) { AddMapping(map_from, map_to); MarkVisibility(map_from, from_visibility); MarkVisibility(map_to, to_visibility); } void IncludePicker::AddSymbolMapping(const string& map_from, + IncludePicker::Visibility from_visibility, const string& map_to, - IncludeVisibility to_visibility) { + IncludePicker::Visibility to_visibility) { CHECK_(IsQuotedInclude(map_to) && "Map values must be quoted includes"); symbol_include_map_[map_from].push_back(map_to); @@ -941,24 +319,7 @@ void IncludePicker::AddSymbolMapping(const string& map_from, MarkVisibility(map_to, to_visibility); } -void IncludePicker::AddIncludeMappings(const IncludeMapEntry* entries, - size_t count) { - for (size_t i = 0; i < count; ++i) { - const IncludeMapEntry& e = entries[i]; - AddIncludeMapping(e.map_from, e.from_visibility, e.map_to, e.to_visibility); - } -} - -void IncludePicker::AddSymbolMappings(const IncludeMapEntry* entries, - size_t count) { - for (size_t i = 0; i < count; ++i) { - const IncludeMapEntry& e = entries[i]; - AddSymbolMapping(e.map_from, e.map_to, e.to_visibility); - } -} - -void IncludePicker::MarkIncludeAsPrivate( - const string& quoted_filepath_pattern) { +void IncludePicker::MarkIncludeAsPrivate(const string& quoted_filepath_pattern) { CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore"); CHECK_(IsQuotedFilepathPattern(quoted_filepath_pattern) && "MIAP takes a quoted filepath pattern"); @@ -1088,8 +449,7 @@ void IncludePicker::AddImplicitThirdPartyMappings() { void IncludePicker::FinalizeAddedIncludes() { CHECK_(!has_called_finalize_added_include_lines_ && "Can't call FAI twice"); - // The map keys may be regular expressions. - // Match those to seen #includes now. + // The map keys may be regular expressions. Match those to seen #includes now. ExpandRegexes(); // We treat third-party code specially, since it's difficult to add @@ -1142,6 +502,33 @@ string IncludePicker::MaybeGetIncludeNameAsWritten( return value ? *value : ""; } +error_code IncludePicker::TryReadMappingFile( + const string& filename, + OwningPtr<MemoryBuffer>& buffer) const { + string absolute_path; + if (IsAbsolutePath(filename)) { + VERRS(5) << "Absolute mapping filename: " << filename << ".\n"; + absolute_path = filename; + } else { + VERRS(5) << "Relative mapping filename: " << filename << ". " + << "Scanning search path.\n"; + // Scan search path + for (Each<string> it(&mapping_file_search_path_); !it.AtEnd(); ++it) { + string candidate = MakeAbsolutePath(*it, filename); + if (llvm::sys::fs::exists(candidate)) { + absolute_path = candidate; + VERRS(5) << "Found mapping file: " << candidate << ".\n"; + break; + } + } + } + + error_code error = MemoryBuffer::getFile(absolute_path, buffer); + VERRS(5) << "Opened mapping file: " << filename << "? " + << error.message() << "\n"; + return error; +} + vector<string> IncludePicker::GetCandidateHeadersForSymbol( const string& symbol) const { CHECK_(has_called_finalize_added_include_lines_ && "Must finalize includes"); @@ -1177,7 +564,7 @@ vector<string> IncludePicker::GetCandidateHeadersForFilepathIncludedFrom( retval = GetCandidateHeadersForFilepath(included_filepath); if (retval.size() == 1) { const string& quoted_header = retval[0]; - if (GetVisibility(quoted_header) == kPrivate) { + if (GetVisibility(quoted_header) == IncludePicker::kPrivate) { VERRS(0) << "Warning: " << "No public header found to replace the private header " << quoted_header << "\n"; @@ -1220,35 +607,24 @@ bool IncludePicker::HasMapping(const string& map_from_filepath, return quoted_to == quoted_from; // indentity mapping, why not? } -// Parses a YAML/JSON file containing mapping directives of various types. -void IncludePicker::AddMappingsFromFile(const string& filename) { - vector<string> default_search_path; - return AddMappingsFromFile(filename, default_search_path); -} - // Parses a YAML/JSON file containing mapping directives of various types: // symbol - symbol name -> quoted include // include - private quoted include -> public quoted include // ref - include mechanism for mapping files, to allow project-specific // groupings -// This private implementation method is recursive and builds the search path -// incrementally. -void IncludePicker::AddMappingsFromFile(const string& filename, - const vector<string>& search_path) { - string absolute_path = FindFileInSearchPath(search_path, filename); - +// We use this to maintain mappings externally, to make it easier +// to update/adjust to local circumstances. +void IncludePicker::AddMappingsFromFile(const string& filename) { OwningPtr<MemoryBuffer> buffer; - error_code error = MemoryBuffer::getFile(absolute_path, buffer); + error_code error = TryReadMappingFile(filename, buffer); if (error) { - errs() << "Cannot open mapping file '" << absolute_path << "': " - << error.message() << ".\n"; + errs() << "Cannot open mapping file '" << filename << "': " + << error.message() << ".\n"; return; } - VERRS(5) << "Adding mappings from file '" << absolute_path << "'.\n"; - SourceMgr source_manager; - Stream json_stream(buffer.take(), source_manager); + Stream json_stream(buffer->getBuffer(), source_manager); document_iterator stream_begin = json_stream.begin(); if (stream_begin == json_stream.end()) @@ -1258,23 +634,24 @@ void IncludePicker::AddMappingsFromFile(const string& filename, Node* root = stream_begin->getRoot(); SequenceNode *array = llvm::dyn_cast<SequenceNode>(root); if (array == NULL) { - json_stream.printError(root, "Root element must be an array."); + errs() << MappingDiag(source_manager, filename, *root, + "Root element must be an array.\n"); return; } for (SequenceNode::iterator it = array->begin(); it != array->end(); ++it) { - Node* current_node = &(*it); + Node& current_node = *it; // Every item must be a JSON object ("mapping" in YAML terms.) - MappingNode* mapping = llvm::dyn_cast<MappingNode>(current_node); + MappingNode* mapping = llvm::dyn_cast<MappingNode>(¤t_node); if (mapping == NULL) { - json_stream.printError(current_node, - "Mapping directives must be objects."); + errs() << MappingDiag(source_manager, filename, current_node, + "Mapping directives must be objects.\n"); return; } for (MappingNode::iterator it = mapping->begin(); - it != mapping->end(); ++it) { + it != mapping->end(); ++it) { // General form is { directive: <data> }. const string directive = GetScalarValue(it->getKey()); @@ -1282,78 +659,85 @@ void IncludePicker::AddMappingsFromFile(const string& filename, // Symbol mapping. vector<string> mapping = GetSequenceValue(it->getValue()); if (mapping.size() != 4) { - json_stream.printError(current_node, - "Symbol mapping expects a value on the form " - "'[from, visibility, to, visibility]'."); + errs() << MappingDiag(source_manager, filename, current_node, + "Symbol mapping expects a value on the form " + "'[from, visibility, to, visibility]'.\n"); return; } - // Ignore unused from-visibility, at some point maybe remove it from the - // mapping file format. + Visibility from_visibility = ParseVisibility(mapping[1]); + if (from_visibility == kUnusedVisibility) { + errs() << MappingDiag(source_manager, filename, current_node, + "Unknown visibility '") << mapping[1] << "'.\n"; + return; + } - IncludeVisibility to_visibility = ParseVisibility(mapping[3]); + Visibility to_visibility = ParseVisibility(mapping[3]); if (to_visibility == kUnusedVisibility) { - json_stream.printError(current_node, - "Unknown visibility '" + mapping[3] + "'."); + errs() << MappingDiag(source_manager, filename, current_node, + "Unknown visibility '") << mapping[3] << "'.\n"; return; } - AddSymbolMapping(mapping[0], mapping[2], to_visibility); + AddSymbolMapping( + mapping[0], + from_visibility, + mapping[2], + to_visibility); } else if (directive == "include") { // Include mapping. vector<string> mapping = GetSequenceValue(it->getValue()); if (mapping.size() != 4) { - json_stream.printError(current_node, - "Include mapping expects a value on the form " - "'[from, visibility, to, visibility]'."); + errs() << MappingDiag(source_manager, filename, current_node, + "Include mapping expects a value on the form " + "'[from, visibility, to, visibility]'.\n"); return; } - IncludeVisibility from_visibility = ParseVisibility(mapping[1]); + Visibility from_visibility = ParseVisibility(mapping[1]); if (from_visibility == kUnusedVisibility) { - json_stream.printError(current_node, - "Unknown visibility '" + mapping[1] + "'."); + errs() << MappingDiag(source_manager, filename, current_node, + "Unknown visibility '") << mapping[1] << "'.\n"; return; } - IncludeVisibility to_visibility = ParseVisibility(mapping[3]); + Visibility to_visibility = ParseVisibility(mapping[3]); if (to_visibility == kUnusedVisibility) { - json_stream.printError(current_node, - "Unknown visibility '" + mapping[3] + "'."); + errs() << MappingDiag(source_manager, filename, current_node, + "Unknown visibility '") << mapping[3] << "'.\n"; return; } - AddIncludeMapping(mapping[0], - from_visibility, - mapping[2], - to_visibility); + AddIncludeMapping( + mapping[0], + from_visibility, + mapping[2], + to_visibility); } else if (directive == "ref") { // Mapping ref. string ref_file = GetScalarValue(it->getValue()); if (ref_file.empty()) { - json_stream.printError(current_node, - "Mapping ref expects a single filename value."); + errs() << MappingDiag(source_manager, filename, current_node, + "Mapping ref expects a single filename value.\n"); return; } // Add the path of the file we're currently processing // to the search path. Allows refs to be relative to referrer. - vector<string> extended_search_path = - ExtendMappingFileSearchPath(search_path, - GetParentPath(absolute_path)); + AddMappingFileSearchPath(GetParentPath(filename)); // Recurse. - AddMappingsFromFile(ref_file, extended_search_path); + AddMappingsFromFile(ref_file); } else { - json_stream.printError(current_node, - "Unknown directive '" + directive + "'."); + errs() << MappingDiag(source_manager, filename, current_node, + "Unknown directive '") << directive << "'.\n"; return; } } } } -IncludeVisibility IncludePicker::ParseVisibility( +IncludePicker::Visibility IncludePicker::ParseVisibility( const string& visibility) const { if (visibility == "private") return kPrivate; @@ -1363,7 +747,7 @@ IncludeVisibility IncludePicker::ParseVisibility( return kUnusedVisibility; } -IncludeVisibility IncludePicker::GetVisibility( +IncludePicker::Visibility IncludePicker::GetVisibility( const string& quoted_include) const { return GetOrDefault( filepath_visibility_map_, quoted_include, kUnusedVisibility); diff --git a/iwyu_include_picker.h b/iwyu_include_picker.h index c126f2d..2215421 100644 --- a/iwyu_include_picker.h +++ b/iwyu_include_picker.h @@ -50,6 +50,13 @@ #include <utility> // for pair #include <vector> // for vector +#include "llvm/ADT/OwningPtr.h" +#include "llvm/Support/MemoryBuffer.h" + +namespace llvm { + class error_code; +} + namespace include_what_you_use { using std::map; @@ -59,15 +66,17 @@ using std::string; using std::vector; -struct IncludeMapEntry; - -enum IncludeVisibility { kUnusedVisibility, kPublic, kPrivate }; +using llvm::OwningPtr; +using llvm::MemoryBuffer; +using llvm::error_code; class IncludePicker { public: + enum Visibility { kUnusedVisibility, kPublic, kPrivate }; + typedef map<string, vector<string> > IncludeMap; // map_from to <map_to,...> - explicit IncludePicker(bool no_default_mappings); + IncludePicker(); // ----- Routines to dynamically modify the include-picker @@ -78,6 +87,9 @@ class IncludePicker { const string& includee_filepath, const string& quoted_include_as_written); + // Add a mapping file search path. + void AddMappingFileSearchPath(const string& path); + // Add this to say "map_to re-exports everything in file map_from". // Both map_to and map_from should be quoted includes. void AddMapping(const string& map_from, const string& map_to); @@ -141,31 +153,16 @@ class IncludePicker { void AddMappingsFromFile(const string& filename); private: - // Private implementation of mapping file parser, which takes - // mapping file search path to allow recursion that builds up - // search path incrementally. - void AddMappingsFromFile(const string& filename, - const vector<string>& search_path); - - // Adds all hard-coded default mappings. - void AddDefaultMappings(); - // Adds a mapping from a one header to another, typically // from a private to a public quoted include. - void AddIncludeMapping( - const string& map_from, IncludeVisibility from_visibility, - const string& map_to, IncludeVisibility to_visibility); + void AddIncludeMapping(const string& map_from, Visibility from_visibility, + const string& map_to, Visibility to_visibility); // Adds a mapping from a a symbol to a quoted include. We use this to // maintain mappings of documented types, e.g. // For std::map<>, include <map>. - void AddSymbolMapping( - const string& map_from, const string& map_to, - IncludeVisibility to_visibility); - - // Adds mappings from sized arrays of IncludeMapEntry. - void AddIncludeMappings(const IncludeMapEntry* entries, size_t count); - void AddSymbolMappings(const IncludeMapEntry* entries, size_t count); + void AddSymbolMapping(const string& map_from, Visibility from_visibility, + const string& map_to, Visibility to_visibility); // Expands the regex keys in filepath_include_map_ and // friend_to_headers_map_ by matching them against all source files @@ -177,15 +174,16 @@ class IncludePicker { void AddImplicitThirdPartyMappings(); // Adds an entry to filepath_visibility_map_, with error checking. - void MarkVisibility(const string& quoted_include, IncludeVisibility vis); + void MarkVisibility(const string& quoted_include, + IncludePicker::Visibility vis); // Parse visibility from a string. Returns kUnusedVisibility if // string is not recognized. - IncludeVisibility ParseVisibility(const string& visibility_str) const; + Visibility ParseVisibility(const string& visibility_str) const; // Return the visibility of a given quoted_include if known, else // kUnusedVisibility. - IncludeVisibility GetVisibility(const string& quoted_include) const; + Visibility GetVisibility(const string& quoted_include) const; // For the given key, return the vector of values associated with // that key, or an empty vector if the key does not exist in the @@ -198,6 +196,11 @@ class IncludePicker { string MaybeGetIncludeNameAsWritten(const string& includer_filepath, const string& includee_filepath) const; + // Scan the search paths for filename. If it exists, put file contents + // in buffer. If not, return the error code. + error_code TryReadMappingFile(const string& filename, + OwningPtr<MemoryBuffer>& buffer) const; + // From symbols to includes. IncludeMap symbol_include_map_; @@ -211,7 +214,7 @@ class IncludePicker { // A map of all quoted-includes to whether they're public or private. // Quoted-includes that are not present in this map are assumed public. - map<string, IncludeVisibility> filepath_visibility_map_; + map<string, Visibility> filepath_visibility_map_; // All the includes we've seen so far, to help with globbing and // other dynamic mapping. For each file, we list who #includes it. @@ -233,6 +236,8 @@ class IncludePicker { // contents of friend_to_headers_map_["@\"foo/bar/.*\""]. map<string, set<string> > friend_to_headers_map_; + vector<string> mapping_file_search_path_; + // Make sure we don't do any non-const operations after finalizing. bool has_called_finalize_added_include_lines_; }; // class IncludePicker diff --git a/iwyu_path_util.cc b/iwyu_path_util.cc index e995830..0043363 100644 --- a/iwyu_path_util.cc +++ b/iwyu_path_util.cc @@ -10,37 +10,19 @@ #include "iwyu_path_util.h" #include <stddef.h> -#include <string.h> // for strlen #include "iwyu_stl_util.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringRef.h" -#include "llvm/ADT/STLExtras.h" #include "llvm/Support/FileSystem.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/PathV2.h" #include "llvm/Support/system_error.h" namespace include_what_you_use { namespace { vector<HeaderSearchPath>* header_search_paths; - -// Please keep this in sync with _SOURCE_EXTENSIONS in fix_includes.py. -const char* source_extensions[] = { - ".c", - ".C", - ".cc", - ".CC", - ".cxx", - ".CXX", - ".cpp", - ".CPP" - ".c++", - ".C++", - ".cp" -}; - } // namespace void SetHeaderSearchPaths(const vector<HeaderSearchPath>& search_paths) { @@ -57,6 +39,10 @@ const vector<HeaderSearchPath>& HeaderSearchPaths() { return *header_search_paths; } +namespace { + +} // namespace + bool IsHeaderFile(string path) { if (EndsWith(path, "\"") || EndsWith(path, ">")) path = path.substr(0, path.length() - 1); @@ -64,14 +50,19 @@ bool IsHeaderFile(string path) { // Some headers don't have an extension (e.g. <string>), or have an // unusual one (the compiler doesn't care), so it's safer to // enumerate non-header extensions instead. - for (size_t i = 0; i < llvm::array_lengthof(source_extensions); ++i) { - if (EndsWith(path, source_extensions[i])) - return false; - } - + if (EndsWith(path, ".cc") || EndsWith(path, ".c") || + EndsWith(path, ".cxx") || EndsWith(path, ".cpp")) + return false; return true; } +string GetCWD() { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) + return cwd; + return ""; +} + string Basename(const string& path) { string::size_type last_slash = path.rfind('/'); if (last_slash != string::npos) { @@ -103,18 +94,15 @@ string GetCanonicalName(string file_path) { file_path = CanonicalizeFilePath(file_path); - bool stripped_ext = StripRight(&file_path, ".h") + StripRight(&file_path, ".h") || StripRight(&file_path, ".hpp") || StripRight(&file_path, ".hxx") || StripRight(&file_path, ".hh") - || StripRight(&file_path, ".inl"); - if (!stripped_ext) { - for (size_t i = 0; i < llvm::array_lengthof(source_extensions); ++i) { - if (StripRight(&file_path, source_extensions[i])) - break; - } - } - + || StripRight(&file_path, ".inl") + || StripRight(&file_path, ".cxx") + || StripRight(&file_path, ".cpp") + || StripRight(&file_path, ".cc") + || StripRight(&file_path, ".c"); StripRight(&file_path, "_unittest") || StripRight(&file_path, "_regtest") || StripRight(&file_path, "_test") diff --git a/iwyu_path_util.h b/iwyu_path_util.h index 1961a92..ce4cf9d 100644 --- a/iwyu_path_util.h +++ b/iwyu_path_util.h @@ -12,6 +12,13 @@ #ifndef DEVTOOLS_MAINTENANCE_INCLUDE_WHAT_YOU_USE_IWYU_PATH_UTIL_H_ #define DEVTOOLS_MAINTENANCE_INCLUDE_WHAT_YOU_USE_IWYU_PATH_UTIL_H_ +#include <limits.h> // for PATH_MAX +#include <string.h> // for strlen +#if defined(_MSC_VER) +#include <direct.h> +#else +#include <unistd.h> // for getcwd +#endif #include <string> // for string, allocator, etc #include <vector> @@ -39,6 +46,9 @@ const vector<HeaderSearchPath>& HeaderSearchPaths(); // quotes or <>) C++ header file. bool IsHeaderFile(string path); +// Return the current working directory of this process. +string GetCWD(); + // If the path has a slash, return the part after the last slash, // else return the input path. string Basename(const string& path); diff --git a/iwyu_preprocessor.cc b/iwyu_preprocessor.cc index 02cb04d..9093e97 100644 --- a/iwyu_preprocessor.cc +++ b/iwyu_preprocessor.cc @@ -34,7 +34,6 @@ using clang::FileEntry; using clang::FileID; -using clang::MacroDirective; using clang::MacroInfo; using clang::Preprocessor; using clang::SourceLocation; @@ -515,14 +514,12 @@ void IwyuPreprocessorInfo::AddDirectInclude( // Called whenever a macro is expanded. Example: when FOO(a, b) is // seen in the source code, where FOO() is a macro #defined earlier, // MacroExpands() will be called once with 'macro_use_token' being -// FOO, and 'directive' containing more information about FOO's +// FOO, and 'macro_def' containing more information about FOO's // definition. void IwyuPreprocessorInfo::MacroExpands(const Token& macro_use_token, - const MacroDirective* directive, - SourceRange range, - const clang::MacroArgs* /*args*/) { + const MacroInfo* macro_def, + SourceRange range) { const FileEntry* macro_file = GetFileEntry(macro_use_token); - const MacroInfo* macro_def = directive->getMacroInfo(); if (ShouldPrintSymbolFromFile(macro_file)) { errs() << "[ Use macro ] " << PrintableLoc(macro_use_token.getLocation()) @@ -536,8 +533,7 @@ void IwyuPreprocessorInfo::MacroExpands(const Token& macro_use_token, } void IwyuPreprocessorInfo::MacroDefined(const Token& id, - const MacroDirective* directive) { - const MacroInfo* macro = directive->getMacroInfo(); + const MacroInfo* macro) { const SourceLocation macro_loc = macro->getDefinitionLoc(); ERRSYM(GetFileEntry(macro_loc)) << "[ #define ] " << PrintableLoc(macro_loc) @@ -580,18 +576,14 @@ void IwyuPreprocessorInfo::Elif(SourceLocation loc, CheckIfOrElif(condition_range); } -void IwyuPreprocessorInfo::Ifdef(SourceLocation loc, - const Token& id, - const MacroDirective* /*directive*/) { +void IwyuPreprocessorInfo::Ifdef(SourceLocation loc, const Token& id) { ERRSYM(GetFileEntry(id.getLocation())) << "[ #ifdef ] " << PrintableLoc(id.getLocation()) << ": " << GetName(id) << "\n"; FindAndReportMacroUse(GetName(id), id.getLocation()); } -void IwyuPreprocessorInfo::Ifndef(SourceLocation loc, - const Token& id, - const MacroDirective* /*directive*/) { +void IwyuPreprocessorInfo::Ifndef(SourceLocation loc, const Token& id) { ERRSYM(GetFileEntry(id.getLocation())) << "[ #ifndef ] " << PrintableLoc(id.getLocation()) << ": " << GetName(id) << "\n"; diff --git a/iwyu_preprocessor.h b/iwyu_preprocessor.h index 4d5decc..2101b72 100644 --- a/iwyu_preprocessor.h +++ b/iwyu_preprocessor.h @@ -66,8 +66,6 @@ #include <vector> // for vector #include "iwyu_output.h" -#include "port.h" - #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" #include "clang/Lex/Preprocessor.h" @@ -169,26 +167,20 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks, protected: // Preprocessor event handlers called by Clang. virtual void MacroExpands(const clang::Token& id, - const clang::MacroDirective* directive, - clang::SourceRange range, - const clang::MacroArgs* args) IWYU_OVERRIDE; - virtual void MacroDefined( - const clang::Token& id, - const clang::MacroDirective* directive) IWYU_OVERRIDE; + const clang::MacroInfo* macro, + clang::SourceRange range); + virtual void MacroDefined(const clang::Token& id, + const clang::MacroInfo* macro); // Not needed for iwyu: // virtual void MacroUndefined(const clang::Token&, const clang::MacroInfo*); virtual void If(clang::SourceLocation loc, - clang::SourceRange condition_range) IWYU_OVERRIDE; + clang::SourceRange condition_range); virtual void Elif(clang::SourceLocation loc, clang::SourceRange condition_range, - clang::SourceLocation if_loc) IWYU_OVERRIDE; - virtual void Ifdef(clang::SourceLocation loc, - const clang::Token& id, - const clang::MacroDirective* directive) IWYU_OVERRIDE; - virtual void Ifndef(clang::SourceLocation loc, - const clang::Token& id, - const clang::MacroDirective* directive) IWYU_OVERRIDE; + clang::SourceLocation if_loc); + virtual void Ifdef(clang::SourceLocation loc, const clang::Token& id); + virtual void Ifndef(clang::SourceLocation loc, const clang::Token& id); // Not needed for iwyu: // virtual void Else(); // virtual void Endif(); @@ -201,15 +193,14 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks, const clang::FileEntry* file, llvm::StringRef search_path, llvm::StringRef relative_path, - const clang::Module* imported) IWYU_OVERRIDE; + const clang::Module* imported); virtual void FileChanged(clang::SourceLocation loc, FileChangeReason reason, clang::SrcMgr::CharacteristicKind file_type, - clang::FileID PrevFID) IWYU_OVERRIDE; - virtual void FileSkipped( - const clang::FileEntry& file, - const clang::Token &filename, - clang::SrcMgr::CharacteristicKind file_type) IWYU_OVERRIDE; + clang::FileID PrevFID); + virtual void FileSkipped(const clang::FileEntry& file, + const clang::Token &filename, + clang::SrcMgr::CharacteristicKind file_type); // FileChanged is actually a multi-plexer for 4 different callbacks. void FileChanged_EnterFile(clang::SourceLocation file_beginning); void FileChanged_ExitToFile(clang::SourceLocation include_loc, @@ -221,7 +212,7 @@ class IwyuPreprocessorInfo : public clang::PPCallbacks, // Clang doc: The handler shall return true if it has pushed any // tokens to be read using e.g. EnterToken or EnterTokenStream. virtual bool HandleComment(clang::Preprocessor& pp, - clang::SourceRange comment_range) IWYU_OVERRIDE; + clang::SourceRange comment_range); private: // Returns true if includee is considered part of the main diff --git a/iwyu_test_util.py b/iwyu_test_util.py index 994b070..5ab726a 100755 --- a/iwyu_test_util.py +++ b/iwyu_test_util.py @@ -82,6 +82,18 @@ _IWYU_PATHS = [ _IWYU_PATH = _GetIwyuPath(_IWYU_PATHS) +def _IsCppSource(file_path): + return (file_path.endswith('.h') or file_path.endswith('.cc') or + file_path.endswith('.c')) + + +def _GetAllCppFilesUnderDir(root_dir): + cpp_files = [] + for (dir, _, files) in os.walk(root_dir): # iterates over all dirs + cpp_files += [os.path.join(dir, f) for f in files if _IsCppSource(f)] + return cpp_files + + def _GetCommandOutput(command): p = subprocess.Popen(command, shell=True, @@ -359,7 +371,7 @@ def _CompareExpectedAndActualSummaries(expected_summaries, actual_summaries): def TestIwyuOnRelativeFile(test_case, cc_file, cpp_files_to_check, - iwyu_flags=None, clang_flags=None, verbose=False): + iwyu_flags=None, verbose=False): """Checks running IWYU on the given .cc file. Args: @@ -368,13 +380,8 @@ def TestIwyuOnRelativeFile(test_case, cc_file, cpp_files_to_check, cpp_files_to_check: A list of filenames for the files to check the diagnostics on, relative to the current dir. iwyu_flags: Extra command-line flags to pass to iwyu. - clang_flags: Extra command-line flags to pass to clang, for example - "-std=c++11". - verbose: Whether to display verbose output. """ iwyu_flags = iwyu_flags or [] # Make sure iwyu_flags is a list. - clang_flags = clang_flags or [] # Make sure clang_flags is a list. - clang_flags = ['-I .'] + clang_flags # Default header search path for tests. # Require verbose level 3 so that we can verify the individual diagnostics. # We allow the level to be overriden by the IWYU_VERBOSE environment @@ -386,8 +393,7 @@ def TestIwyuOnRelativeFile(test_case, cc_file, cpp_files_to_check, iwyu_flags = ['-Xiwyu ' + flag for flag in iwyu_flags] # TODO(csilvers): verify that has exit-status 0. - cmd = '%s %s %s %s' % ( - _IWYU_PATH, ' '.join(iwyu_flags), ' '.join(clang_flags), cc_file) + cmd = '%s %s -I . %s' % (_IWYU_PATH, ' '.join(iwyu_flags), cc_file) if verbose: print('>>> Running %s' % cmd) output = _GetCommandOutput(cmd) @@ -406,3 +412,14 @@ def TestIwyuOnRelativeFile(test_case, cc_file, cpp_files_to_check, _GetActualSummaries(output)) test_case.assertTrue(not failures, ''.join(failures)) + + +# TODO(dsturtevant): Move all tests using this function to the test directory +# harness, then get rid of it. +def TestIwyuOnFile(test_case, relative_test_dir, cc_file, iwyu_flags=None): + """Checks running IWYU on the .cc file in the given directory.""" + + TestIwyuOnRelativeFile(test_case, + os.path.join(relative_test_dir, cc_file), + _GetAllCppFilesUnderDir(relative_test_dir), + iwyu_flags) diff --git a/make_readme.py b/make_readme.py deleted file mode 100644 index e737892..0000000 --- a/make_readme.py +++ /dev/null @@ -1,142 +0,0 @@ -#!/usr/bin/python - -##===--------- make_readme.py - generate README from Wiki sources ---------===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -import os -import re -import sys -import glob -import textwrap -from datetime import datetime - - -_USAGE = """\ -USAGE: -make_readme.py <path to wiki checkout> - -Turn the entire IWYU Wiki into formatted text suitable for README.txt by -removing/transforming selected Wiki markup. - -Example: -include-what-you-use$ ./make_readme.py ./wiki > README.txt -""" - - -# fixes all have the following traits: -# - take a line and return one or more lines as a single string -# - return None if the line is to be deleted -# - return an empty string if the line is to be left blank -def FixCodeBlock(line): - if line.startswith('{{{') or line.startswith('}}}'): - return '' - - return line - - -def FixNewLine(line): - return line.strip('\r').strip('\n') - - -def FixDirectives(line): - if line.startswith('#summary') or line.startswith('#labels'): - return None - - return line - - -def FixLinks(line): - return re.sub(R'\[.*?\s(.*?)\]', R'\1', line) - - -def FixBackticks(line): - return line.replace('`', '') - - -def FixLinewrap(line): - return textwrap.fill(line, 80) - - -def ApplyFixes(line, fixes): - for fix in fixes: - if line: - line = fix(line) - - return line - - -def Unwikified(filename): - fixes = [FixCodeBlock, FixDirectives, FixLinks, FixBackticks, - FixNewLine, FixLinewrap] - - readme = [] - - with open(filename, 'r') as stream: - for line in stream.readlines(): - line = ApplyFixes(line, fixes) - if line is not None: - readme.append(line) - - return '\n'.join(readme) - - -def Heading(): - now = datetime.utcnow().replace(microsecond=0) - - buf = [] - buf.append('-' * 80) - buf.append(' Include What You Use') - buf.append('-' * 80) - buf.append('') - buf.append('This README was generated from the Wiki contents at') - buf.append('http://code.google.com/p/include-what-you-use/w/ on %s UTC.' - % now.isoformat(' ')) - - return '\n'.join(buf) - - -def ListWikiPages(wiki_pattern): - def Prioritize(path): - name = os.path.basename(path) - prioritized = ['InstructionsForUsers.wiki', - 'InstructionsForDevelopers.wiki', - 'WhyIWYU.wiki'] - - if name in prioritized: - priority = prioritized.index(name) - else: - priority = len(prioritized) - - return priority - - excluded = [] - page_paths = [os.path.abspath(filename) - for filename in glob.iglob(wiki_pattern) - if not os.path.basename(filename) in excluded] - - return sorted(page_paths, key=Prioritize) - - -def main(argv): - if len(argv) != 2: - print(_USAGE) - return 1 - - print(Heading()) - - path = argv[1] - pattern = os.path.join(path, '*.wiki') - for page_path in ListWikiPages(pattern): - print(Unwikified(page_path)) - - return 0 - - -if __name__ == '__main__': - sys.exit(main(sys.argv)) @@ -14,23 +14,6 @@ #include <stdlib.h> // for abort #include <iostream> -// Portable stub for Clang's __has_feature. -#ifndef __has_feature -# define __has_feature(x) 0 -#endif - -// Portable override keyword. -// Use to mark virtual methods as overriding a base class method, -// compiler will complain if method does not exist in base class. -#if (defined(_MSC_VER) || __has_feature(cxx_override_control)) -#define IWYU_OVERRIDE override -#else -#define IWYU_OVERRIDE -#endif - -// Count of statically allocated array. -#define IWYU_ARRAYSIZE(arr) sizeof(arr) / sizeof(*arr) - namespace include_what_you_use { // Helper class that allows programmers to log extra information in CHECK_s. @@ -66,20 +49,23 @@ class OstreamVoidifier { #if defined(_WIN32) -#define snprintf _snprintf +# define NOMINMAX +# include <windows.h> -#define NOMINMAX // Prevent Windows headers from redefining min/max. -#include "Shlwapi.h" // for PathMatchSpec +# define getcwd _getcwd +# define snprintf _snprintf -// This undef is necessary to prevent conflicts between llvm -// and Windows headers. -// objbase.h has #define interface struct. -#undef interface +# include "Shlwapi.h" // for PathMatchSpec inline bool GlobMatchesPath(const char *glob, const char *path) { return PathMatchSpec(path, glob); } +// FIXME: This undef is necessary to prevent conflicts between llvm +// and Windows headers. Eventually fnmatch functionality +// should be wrapped inside llvm's PathV2 library. +# undef interface // used in Shlwapi.h + #else // #if defined(_WIN32) #include <fnmatch.h> diff --git a/run_iwyu_tests.py b/run_iwyu_tests.py index f972e2e..72a3325 100755 --- a/run_iwyu_tests.py +++ b/run_iwyu_tests.py @@ -34,11 +34,6 @@ def CheckAlsoExtension(extension): return '--check_also="%s"' % os.path.join(TEST_ROOTDIR, '*' + extension) -def MappingFile(filename): - """Return a suitable iwyu flag for adding the given mapping file.""" - return '--mapping_file=%s' % os.path.join(TEST_ROOTDIR, filename) - - class OneIwyuTest(unittest.TestCase): """Superclass for tests. A subclass per test-file is created at runtime.""" @@ -49,28 +44,20 @@ class OneIwyuTest(unittest.TestCase): # key=cc-filename (relative to TEST_ROOTDIR), value=list of flags. flags_map = { 'backwards_includes.cc': [CheckAlsoExtension('-d*.h')], - 'badinc.cc': [MappingFile('badinc.imp')], 'check_also.cc': [CheckAlsoExtension('-d1.h')], 'implicit_ctor.cc': [CheckAlsoExtension('-d1.h')], 'iwyu_stricter_than_cpp.cc': [CheckAlsoExtension('-*[^0-9].h'), CheckAlsoExtension('-d2.h')], - 'keep_mapping.cc': [CheckAlsoExtension('-public.h'), - MappingFile('keep_mapping.imp')], + 'keep_mapping.cc': [CheckAlsoExtension('-public.h')], 'macro_location.cc': [CheckAlsoExtension('-d2.h')], 'non_transitive_include.cc': [CheckAlsoExtension('-d*.h'), '--transitive_includes_only'], 'no_h_includes_cc.cc': [CheckAlsoExtension('.c')], 'overloaded_class.cc': [CheckAlsoExtension('-i1.h')], } - clang_flags_map = { - 'auto_type_within_template.cc': ['-std=c++11'], - 'conversion_ctor.cc': ['-std=c++11'], - } # Internally, we like it when the paths start with TEST_ROOTDIR. self._iwyu_flags_map = dict((os.path.join(TEST_ROOTDIR, k), v) for (k,v) in flags_map.items()) - self._clang_flags_map = dict((os.path.join(TEST_ROOTDIR, k), v) - for (k,v) in clang_flags_map.items()) def RunOneTest(self, filename): logging.info('Testing iwyu on %s', filename) @@ -97,12 +84,8 @@ class OneIwyuTest(unittest.TestCase): if iwyu_flags: logging.info('%s: Using iwyu flags %s', filename, str(iwyu_flags)) - clang_flags = self._clang_flags_map.get(filename, None) - if clang_flags: - logging.info('%s: Using clang flags %s', filename, str(clang_flags)) - iwyu_test_util.TestIwyuOnRelativeFile(self, filename, files_to_check, - iwyu_flags, clang_flags, verbose=True) + iwyu_flags, verbose=True) def RegisterFilesForTesting(): diff --git a/tests/auto_type_within_template.cc b/tests/auto_type_within_template.cc deleted file mode 100644 index 4c19cfd..0000000 --- a/tests/auto_type_within_template.cc +++ /dev/null @@ -1,22 +0,0 @@ -//===--- auto_type_within_template.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. -// -//===----------------------------------------------------------------------===// - -// Tests that IWYU doesn't crash when auto type is within template and has no -// deduced type. - -template<typename T> -void foo(T x) { - auto y = x; -} - -/**** IWYU_SUMMARY - -(tests/auto_type_within_template.cc has correct #includes/fwd-decls) - -***** IWYU_SUMMARY */ diff --git a/tests/badinc.imp b/tests/badinc.imp deleted file mode 100644 index e11c08c..0000000 --- a/tests/badinc.imp +++ /dev/null @@ -1,5 +0,0 @@ -# Header mappings for IWYU tests. -[ - { include: ["\"tests/badinc-private.h\"", "private", "\"tests/badinc-inl.h\"", "public"] }, - { include: ["\"tests/badinc-private2.h\"", "private", "\"tests/badinc-inl.h\"", "public"] } -] diff --git a/tests/conversion_ctor.cc b/tests/conversion_ctor.cc deleted file mode 100644 index 15205f2..0000000 --- a/tests/conversion_ctor.cc +++ /dev/null @@ -1,38 +0,0 @@ -//===--- conversion_ctor.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. -// -//===----------------------------------------------------------------------===// - -// The smallest repro case for issue #89: -// http://code.google.com/p/include-what-you-use/issues/detail?id=89 - -#include "tests/direct.h" - -// IWYU: IndirectClass is...*indirect.h -IndirectClass ic; // this triggers generation of implicit move constructor - -// IWYU: IndirectClass needs a declaration -char Foo(IndirectClass); // this checks if IndirectClass has an implicit - // conversion constructor, which misfires because - // there's an implicit move constructor. - -// The patch to issue #89 fixes this by having iwyu_ast_util.cc's -// HasImplicitConversionCtor not treat implicit move constructors as -// implicit conversion constructors. - -/**** IWYU_SUMMARY - -tests/conversion_ctor.cc should add these lines: -#include "tests/indirect.h" - -tests/conversion_ctor.cc should remove these lines: -- #include "tests/direct.h" // lines XX-XX - -The full include-list for tests/conversion_ctor.cc: -#include "tests/indirect.h" // for IndirectClass - -***** IWYU_SUMMARY */ diff --git a/tests/cvr-base.h b/tests/cvr-base.h deleted file mode 100644 index e4f2987..0000000 --- a/tests/cvr-base.h +++ /dev/null @@ -1,15 +0,0 @@ -//===--- cvr-base.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. -// -//===----------------------------------------------------------------------===// - -#ifndef CVR_BASE_H -#define CVR_BASE_H - -class Base {}; - -#endif diff --git a/tests/cvr-class.h b/tests/cvr-class.h deleted file mode 100644 index 52dbef7..0000000 --- a/tests/cvr-class.h +++ /dev/null @@ -1,15 +0,0 @@ -//===--- cvr-class.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. -// -//===----------------------------------------------------------------------===// - -#ifndef CVR_CLASS_H -#define CVR_CLASS_H - -class Class {}; - -#endif diff --git a/tests/cvr-derived.h b/tests/cvr-derived.h deleted file mode 100644 index c064c41..0000000 --- a/tests/cvr-derived.h +++ /dev/null @@ -1,17 +0,0 @@ -//===--- cvr-derived.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. -// -//===----------------------------------------------------------------------===// - -#ifndef CVR_DERIVED_H -#define CVR_DERIVED_H - -#include "tests/cvr-base.h" - -class Derived : public Base {}; - -#endif diff --git a/tests/cvr.cc b/tests/cvr.cc deleted file mode 100644 index 9f7532a..0000000 --- a/tests/cvr.cc +++ /dev/null @@ -1,49 +0,0 @@ -//===--- cvr.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. -// -//===----------------------------------------------------------------------===// - -#include "tests/cvr-derived.h" // for Derived -#include "tests/cvr-class.h" // for Class - -class Base; - -class ReturnsBase { - virtual Base* non_covariant() = 0; - - virtual Base* covariant_derived() = 0; - virtual const Class* covariant_cv_qual() = 0; -}; - -class ReturnsDerived : public ReturnsBase { - // Normal case, do not trigger covariant return types. - // This should require only a forward declaration of Base. - Base* non_covariant() { - return 0; - } - - // C++ [class.virtual]p7, second bullet - // Trigger covariant return types: - // Base is an unambiguous and accessible direct or indirect base class of - // Derived. - Derived* covariant_derived() { - return 0; - } - - // C++ [class.virtual]p7, third bullet - // Trigger covariant return types: - // Class* has less cv-qualification than const Class*. - Class* covariant_cv_qual() { - return 0; - } -}; - -/**** IWYU_SUMMARY - -(tests/cvr.cc has correct #includes/fwd-decls) - -***** IWYU_SUMMARY */ diff --git a/tests/keep_mapping.imp b/tests/keep_mapping.imp deleted file mode 100644 index 08014f0..0000000 --- a/tests/keep_mapping.imp +++ /dev/null @@ -1,5 +0,0 @@ -# Header mappings for IWYU tests. -[ - { include: ["@\"tests/keep_mapping-private.*\"", "private", "\"tests/keep_mapping-public.h\"", "public"] }, - { include: ["\"tests/keep_mapping-priv.h\"", "private", "\"tests/keep_mapping-public.h\"", "public"] } -] |