Specify public STL headers explicitly (issue #132).

Add STL mapping suitable for different STL implementations instead of relying
on libstdc++ mappings to provide all public STL headers implicitly.
This commit is contained in:
Volodymyr Sapsai 2014-09-28 17:54:48 +00:00
parent 461e0eed28
commit 147dfb6dd9
5 changed files with 123 additions and 36 deletions

View File

@ -198,40 +198,4 @@
{ include: [ "<linux/limits.h>", private, "<limits.h>", public ] }, # PATH_MAX
{ include: [ "<linux/prctl.h>", private, "<sys/prctl.h>", public ] },
{ include: [ "<sys/ucontext.h>", private, "<ucontext.h>", public ] },
# 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
{ include: [ "<assert.h>", public, "<cassert>", public ] },
{ include: [ "<complex.h>", public, "<ccomplex>", public ] },
{ include: [ "<ctype.h>", public, "<cctype>", public ] },
{ include: [ "<errno.h>", public, "<cerrno>", public ] },
{ include: [ "<fenv.h>", public, "<cfenv>", public ] },
{ include: [ "<float.h>", public, "<cfloat>", public ] },
{ include: [ "<inttypes.h>", public, "<cinttypes>", public ] },
{ include: [ "<iso646.h>", public, "<ciso646>", public ] },
{ include: [ "<limits.h>", public, "<climits>", public ] },
{ include: [ "<locale.h>", public, "<clocale>", public ] },
{ include: [ "<math.h>", public, "<cmath>", public ] },
{ include: [ "<setjmp.h>", public, "<csetjmp>", public ] },
{ include: [ "<signal.h>", public, "<csignal>", public ] },
{ include: [ "<stdalign.h>", public, "<cstdalign>", public ] },
{ include: [ "<stdarg.h>", public, "<cstdarg>", public ] },
{ include: [ "<stdbool.h>", public, "<cstdbool>", public ] },
{ include: [ "<stddef.h>", public, "<cstddef>", public ] },
{ include: [ "<stdint.h>", public, "<cstdint>", public ] },
{ include: [ "<stdio.h>", public, "<cstdio>", public ] },
{ include: [ "<stdlib.h>", public, "<cstdlib>", public ] },
{ include: [ "<string.h>", public, "<cstring>", public ] },
{ include: [ "<tgmath.h>", public, "<ctgmath>", public ] },
{ include: [ "<time.h>", public, "<ctime>", public ] },
{ include: [ "<uchar.h>", public, "<cuchar>", public ] },
{ include: [ "<wchar.h>", public, "<cwchar>", public ] },
{ include: [ "<wctype.h>", public, "<cwctype>", public ] },
]

View File

@ -3,5 +3,6 @@
{ ref: gcc.libc.imp },
{ ref: gcc.symbols.imp },
{ ref: gcc.stl.headers.imp },
{ ref: stl.c.headers.imp },
{ ref: third_party.imp }
]

View File

@ -429,6 +429,9 @@ const IncludeMapEntry libc_include_map[] = {
{ "<linux/limits.h>", kPrivate, "<limits.h>", kPublic }, // PATH_MAX
{ "<linux/prctl.h>", kPrivate, "<sys/prctl.h>", kPublic },
{ "<sys/ucontext.h>", kPrivate, "<ucontext.h>", kPublic },
};
const IncludeMapEntry stdlib_c_include_map[] = {
// Allow the C++ wrappers around C files. Without these mappings,
// if you #include <cstdio>, iwyu will tell you to replace it with
// <stdio.h>, which is where the symbols are actually defined. We
@ -439,6 +442,10 @@ const IncludeMapEntry libc_include_map[] = {
// assert.h with cassert, you'd change it to a public->private
// mapping.) Here is how I identified the files to map:
// $ for i in /usr/include/c++/4.4/c* ; do ls /usr/include/`basename $i | cut -b2-`.h /usr/lib/gcc/*/4.4/include/`basename $i | cut -b2-`.h 2>/dev/null ; done
//
// These headers are defined in C++14 [headers]p3. You can get them with
// $ sed -n '/begin{floattable}.*{tab:cpp.c.headers}/,/end{floattable}/p' lib-intro.tex | grep tcode | perl -nle 'm/tcode{<c(.*)>}/ && print qq@ { "<$1.h>", kPublic, "<c$1>", kPublic },@' | sort
// on https://github.com/cplusplus/draft/blob/master/source/lib-intro.tex
{ "<assert.h>", kPublic, "<cassert>", kPublic },
{ "<complex.h>", kPublic, "<ccomplex>", kPublic },
{ "<ctype.h>", kPublic, "<cctype>", kPublic },
@ -467,6 +474,65 @@ const IncludeMapEntry libc_include_map[] = {
{ "<wctype.h>", kPublic, "<cwctype>", kPublic },
};
const char* stdlib_cpp_public_headers[] = {
// These headers are defined in C++14 [headers]p2. You can get them with
// $ sed -n '/begin{floattable}.*{tab:cpp.library.headers}/,/end{floattable}/p' lib-intro.tex | grep tcode | perl -nle 'm/tcode{(.*)}/ && print qq@ "$1",@' | sort
// on https://github.com/cplusplus/draft/blob/master/source/lib-intro.tex
"<algorithm>",
"<array>",
"<atomic>",
"<bitset>",
"<chrono>",
"<codecvt>",
"<complex>",
"<condition_variable>",
"<deque>",
"<exception>",
"<forward_list>",
"<fstream>",
"<functional>",
"<future>",
"<initializer_list>",
"<iomanip>",
"<ios>",
"<iosfwd>",
"<iostream>",
"<istream>",
"<iterator>",
"<limits>",
"<list>",
"<locale>",
"<map>",
"<memory>",
"<mutex>",
"<new>",
"<numeric>",
"<ostream>",
"<queue>",
"<random>",
"<ratio>",
"<regex>",
"<scoped_allocator>",
"<set>",
"<sstream>",
"<stack>",
"<stdexcept>",
"<streambuf>",
"<string>",
"<strstream>",
"<system_error>",
"<thread>",
"<tuple>",
"<type_traits>",
"<typeindex>",
"<typeinfo>",
"<unordered_map>",
"<unordered_set>",
"<utility>",
"<valarray>",
"<vector>",
};
// 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)
@ -890,8 +956,13 @@ void IncludePicker::AddDefaultMappings() {
AddIncludeMappings(libc_include_map,
IWYU_ARRAYSIZE(libc_include_map));
AddIncludeMappings(stdlib_c_include_map,
IWYU_ARRAYSIZE(stdlib_c_include_map));
AddIncludeMappings(libstdcpp_include_map,
IWYU_ARRAYSIZE(libstdcpp_include_map));
AddPublicIncludes(stdlib_cpp_public_headers,
IWYU_ARRAYSIZE(stdlib_cpp_public_headers));
}
void IncludePicker::MarkVisibility(
@ -1005,6 +1076,13 @@ void IncludePicker::AddSymbolMappings(const IncludeMapEntry* entries,
}
}
void IncludePicker::AddPublicIncludes(const char** includes, size_t count) {
for (size_t i = 0; i < count; ++i) {
const char* include = includes[i];
MarkVisibility(include, kPublic);
}
}
void IncludePicker::MarkIncludeAsPrivate(
const string& quoted_filepath_pattern) {
CHECK_(!has_called_finalize_added_include_lines_ && "Can't mutate anymore");

View File

@ -173,6 +173,8 @@ class IncludePicker {
void AddIncludeMappings(const IncludeMapEntry* entries, size_t count);
void AddSymbolMappings(const IncludeMapEntry* entries, size_t count);
void AddPublicIncludes(const char** includes, size_t count);
// Expands the regex keys in filepath_include_map_ and
// friend_to_headers_map_ by matching them against all source files
// seen by iwyu.

42
stl.c.headers.imp Normal file
View File

@ -0,0 +1,42 @@
[
# Allow the C++ wrappers around C files. Without these mappings,
# if you #include <cstdio>, iwyu will tell you to replace it with
# <stdio.h>, which is where the symbols are actually defined. We
# inhibit that behavior to keep the <cstdio> alone. Note this is a
# public-to-public mapping: we don't want to *replace* <assert.h>
# with <cassert>, we just want to avoid suggesting changing
# <cassert> back to <assert.h>. (If you *did* want to replace
# assert.h with cassert, you'd change it to a public->private
# mapping.) Here is how I identified the files to map:
# $ for i in /usr/include/c++/4.4/c* ; do ls /usr/include/`basename $i | cut -b2-`.h /usr/lib/gcc/*/4.4/include/`basename $i | cut -b2-`.h 2>/dev/null ; done
#
# These headers are defined in C++14 [headers]p3. You can get them with
# $ sed -n '/begin{floattable}.*{tab:cpp.c.headers}/,/end{floattable}/p' lib-intro.tex | grep tcode | perl -nle 'm/tcode{<c(.*)>}/ && print qq@ { include: [ "<$1.h>", public, "<c$1>", public ] },@' | sort
# on https://github.com/cplusplus/draft/blob/master/source/lib-intro.tex
{ include: [ "<assert.h>", public, "<cassert>", public ] },
{ include: [ "<complex.h>", public, "<ccomplex>", public ] },
{ include: [ "<ctype.h>", public, "<cctype>", public ] },
{ include: [ "<errno.h>", public, "<cerrno>", public ] },
{ include: [ "<fenv.h>", public, "<cfenv>", public ] },
{ include: [ "<float.h>", public, "<cfloat>", public ] },
{ include: [ "<inttypes.h>", public, "<cinttypes>", public ] },
{ include: [ "<iso646.h>", public, "<ciso646>", public ] },
{ include: [ "<limits.h>", public, "<climits>", public ] },
{ include: [ "<locale.h>", public, "<clocale>", public ] },
{ include: [ "<math.h>", public, "<cmath>", public ] },
{ include: [ "<setjmp.h>", public, "<csetjmp>", public ] },
{ include: [ "<signal.h>", public, "<csignal>", public ] },
{ include: [ "<stdalign.h>", public, "<cstdalign>", public ] },
{ include: [ "<stdarg.h>", public, "<cstdarg>", public ] },
{ include: [ "<stdbool.h>", public, "<cstdbool>", public ] },
{ include: [ "<stddef.h>", public, "<cstddef>", public ] },
{ include: [ "<stdint.h>", public, "<cstdint>", public ] },
{ include: [ "<stdio.h>", public, "<cstdio>", public ] },
{ include: [ "<stdlib.h>", public, "<cstdlib>", public ] },
{ include: [ "<string.h>", public, "<cstring>", public ] },
{ include: [ "<tgmath.h>", public, "<ctgmath>", public ] },
{ include: [ "<time.h>", public, "<ctime>", public ] },
{ include: [ "<uchar.h>", public, "<cuchar>", public ] },
{ include: [ "<wchar.h>", public, "<cwchar>", public ] },
{ include: [ "<wctype.h>", public, "<cwctype>", public ] },
]