summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKim Gräsman <kim@mvps.org>2013-06-19 11:24:25 +0000
committerKim Gräsman <kim@mvps.org>2013-06-19 11:24:25 +0000
commit9615af8768012d30e0379c66c09e39886b813bee (patch)
treead5d7378473fa8fd438c3a9c25101d535a10ca3d
parentb1368d82903fce243318b8477c7099ce20903f20 (diff)
Tag Clang 3.2 release branch.clang_3.2
-rw-r--r--CMakeLists.txt82
-rw-r--r--Makefile11
-rw-r--r--README.txt1479
-rwxr-xr-xfix_includes.py35
-rw-r--r--gcc.stl.headers.imp14
-rw-r--r--google.imp8
-rw-r--r--iwyu.cc116
-rw-r--r--iwyu_ast_util.cc43
-rw-r--r--iwyu_ast_util.h5
-rw-r--r--iwyu_driver.cc5
-rw-r--r--iwyu_globals.cc28
-rw-r--r--iwyu_globals.h4
-rw-r--r--iwyu_include_picker.cc840
-rw-r--r--iwyu_include_picker.h59
-rw-r--r--iwyu_path_util.cc54
-rw-r--r--iwyu_path_util.h10
-rw-r--r--iwyu_preprocessor.cc20
-rw-r--r--iwyu_preprocessor.h37
-rwxr-xr-xiwyu_test_util.py33
-rw-r--r--make_readme.py142
-rw-r--r--port.h34
-rwxr-xr-xrun_iwyu_tests.py21
-rw-r--r--tests/auto_type_within_template.cc22
-rw-r--r--tests/badinc.imp5
-rw-r--r--tests/conversion_ctor.cc38
-rw-r--r--tests/cvr-base.h15
-rw-r--r--tests/cvr-class.h15
-rw-r--r--tests/cvr-derived.h17
-rw-r--r--tests/cvr.cc49
-rw-r--r--tests/keep_mapping.imp5
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
diff --git a/Makefile b/Makefile
index c9234c9..efa16c8 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/README.txt b/README.txt
index 7805047..ebc9007 100644
--- a/README.txt
+++ b/README.txt
@@ -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 ] }
+]
diff --git a/iwyu.cc b/iwyu.cc
index f40b5bd..74adb95 100644
--- a/iwyu.cc
+++ b/iwyu.cc
@@ -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>(&current_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))
diff --git a/port.h b/port.h
index 31ac28b..9316261 100644
--- a/port.h
+++ b/port.h
@@ -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"] }
-]