303 lines
13 KiB
C++
303 lines
13 KiB
C++
//===--- iwyu_include_picker.h - map to canonical #includes for iwyu ------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// The include-picker provides a list of candidate #include-lines
|
|
// that iwyu can suggest in order to include a particular symbol
|
|
// or file.
|
|
//
|
|
// It seems like the 'file' case would be easy ("to include
|
|
// /usr/include/math.h, say '#include <math.h>"), but it's
|
|
// not because many header files are private, and should not
|
|
// be included by users directly. A private header will have
|
|
// one or (occassionally) more public headers that it maps to.
|
|
// The include-picker keeps track of these mappings.
|
|
//
|
|
// It's also possible for a public file to have an include-picker
|
|
// mapping. This means: "it's ok to #include this file directly, but
|
|
// you can also get the contents of this file by #including this other
|
|
// file as well." One example is that <ostream> maps to both
|
|
// <ostream> and <iostream>. Other parts of iwyu can decide which
|
|
// #include to suggest based on its own heuristics (whether the file
|
|
// already needs to #include <iostream> for some other reason, for
|
|
// instance).
|
|
//
|
|
// Some of these mappings are hard-coded, based on my own examination
|
|
// of gcc headers on ubuntu. Some mappings are determined at runtime,
|
|
// based on #pragmas or other writeup in the source files themselves.
|
|
//
|
|
// Mapping a symbol to a file has the same issues. In most cases, a
|
|
// symbol maps to the file that defines it, and iwyu_include_picker
|
|
// has nothing useful to say. But some symbols -- which we hard-code
|
|
// -- can be provided by several files. NULL is a canonical example
|
|
// of this.
|
|
//
|
|
// The include-picker also provides some helper functions for
|
|
// converting from file-paths to #include paths, including, routines to
|
|
// normalize a file-path to get rid of /usr/include/ prefixes.
|
|
|
|
#ifndef INCLUDE_WHAT_YOU_USE_IWYU_INCLUDE_PICKER_H_
|
|
#define INCLUDE_WHAT_YOU_USE_IWYU_INCLUDE_PICKER_H_
|
|
|
|
#include <map> // for map, map<>::value_compare
|
|
#include <set> // for set
|
|
#include <string> // for string
|
|
#include <utility> // for pair
|
|
#include <vector> // for vector
|
|
|
|
namespace clang {
|
|
class FileEntry;
|
|
} // namespace clang
|
|
|
|
namespace include_what_you_use {
|
|
|
|
using std::map;
|
|
using std::pair;
|
|
using std::set;
|
|
using std::string;
|
|
|
|
using std::vector;
|
|
|
|
struct IncludeMapEntry;
|
|
|
|
enum class RegexDialect;
|
|
enum IncludeVisibility { kUnusedVisibility, kPublic, kPrivate };
|
|
|
|
// When a symbol or file is mapped to an include, that include is represented
|
|
// by this struct. It always has a quoted_include and may also have a path
|
|
// (depending on its origin).
|
|
struct MappedInclude {
|
|
explicit MappedInclude(const string& quoted_include,
|
|
const string& path = {});
|
|
|
|
string quoted_include;
|
|
string path;
|
|
|
|
bool HasAbsoluteQuotedInclude() const;
|
|
};
|
|
|
|
class IncludePicker {
|
|
public:
|
|
// The keys are either symbol names or quoted includes, and the values are
|
|
// lists of candidate public headers to include for symbol or quoted include.
|
|
typedef map<string, vector<MappedInclude>> IncludeMap;
|
|
|
|
// Used to track visibility as specified either in mapping files or via
|
|
// pragmas. The keys are quoted includes or paths. The values are the
|
|
// visibility of the respective files.
|
|
typedef map<string, IncludeVisibility> VisibilityMap;
|
|
|
|
IncludePicker(bool no_default_mappings, RegexDialect regex_dialect);
|
|
|
|
// ----- Routines to dynamically modify the include-picker
|
|
|
|
// Call this for every #include seen during iwyu analysis. The
|
|
// include-picker can use this data to better suggest #includes,
|
|
// perhaps.
|
|
void AddDirectInclude(const string& includer_filepath,
|
|
const string& includee_filepath,
|
|
const string& quoted_include_as_written);
|
|
|
|
// Add this to say "map_to re-exports everything in file map_from".
|
|
// map_from should be a quoted include.
|
|
void AddMapping(const string& map_from, const MappedInclude& map_to);
|
|
|
|
// Indicate that the given quoted include should be considered
|
|
// a "private" include. If possible, we use the include-picker
|
|
// mappings to map such includes to public (not-private) includes.
|
|
void MarkIncludeAsPrivate(const string& quoted_include);
|
|
|
|
// Indicate that the given path should be considered
|
|
// a "private" include. If possible, we use the include-picker
|
|
// mappings to map such includes to public (not-private) includes.
|
|
void MarkPathAsPrivate(const string& path);
|
|
|
|
// Add this to say that "any file whose name matches the
|
|
// friend_regex is allowed to include includee_filepath". The regex
|
|
// uses the POSIX Entended Regular Expression syntax and should
|
|
// match a quoted-include (starting and ending with "" or <>).
|
|
void AddFriendRegex(const string& includee_filepath,
|
|
const string& quoted_friend_regex);
|
|
|
|
// Call this after iwyu preprocessing is done. No more calls to
|
|
// AddDirectInclude() or AddMapping() are allowed after this.
|
|
void FinalizeAddedIncludes();
|
|
|
|
// ----- Include-picking API
|
|
|
|
// Returns the set of all public header files that 'provide' the
|
|
// given symbol. For instance, NULL can map to stddef.h, stdlib.h,
|
|
// etc. Most symbols don't have pre-defined headers they map to,
|
|
// and we return the empty vector in that case. Ordering is
|
|
// important (which is why we return a vector, not a set): all else
|
|
// being equal, the first element of the vector is the "best" (or
|
|
// most standard) header for the symbol.
|
|
vector<MappedInclude> GetCandidateHeadersForSymbol(
|
|
const string& symbol) const;
|
|
|
|
// As above, but given a specific including header it is possible to convert
|
|
// mapped includes to quoted include strings (because we can for example know
|
|
// the correct relative path for ""-style includes).
|
|
vector<string> GetCandidateHeadersForSymbolUsedFrom(
|
|
const string& symbol, const string& including_filepath) const;
|
|
|
|
// Returns the set of all public header files that a given header
|
|
// file -- specified as a full path -- would map to, as a set of
|
|
// MappedIncludes. If the include-picker has
|
|
// no mapping information for this file, the return vector has just
|
|
// the input file (now include-quoted). Ordering is important
|
|
// (which is why we return a vector, not a set): all else being
|
|
// equal, the first element of the vector is the "best" (or most
|
|
// standard) header for the input header.
|
|
vector<MappedInclude> GetCandidateHeadersForFilepath(
|
|
const string& filepath, const string& including_filepath = "") const;
|
|
|
|
// This allows for special-casing of GetCandidateHeadersForFilepath
|
|
// -- it's the same, but you give it the filepath that's doing the
|
|
// #including. This lets us give a different answer for different
|
|
// call-sites. For instance, "foo/internal/bar.h" is a fine
|
|
// candidate header when #included from "foo/internal/baz.h", but
|
|
// not when #included from "qux/quux.h". In the common case there's
|
|
// no special-casing, and this falls back on
|
|
// GetCandidateHeadersForFilepath().
|
|
// Furthermore, knowing the including file allows use to convert each
|
|
// MappedInclude in the result to a simple string (quoted include).
|
|
vector<string> GetCandidateHeadersForFilepathIncludedFrom(
|
|
const string& included_filepath, const string& including_filepath) const;
|
|
|
|
// Returns true if there is a mapping (possibly indirect) from
|
|
// map_from to map_to. This means that to_file 're-exports' all the
|
|
// symbols from from_file. Both map_from_filepath and
|
|
// map_to_filepath should be full file-paths.
|
|
bool HasMapping(const string& map_from_filepath,
|
|
const string& map_to_filepath) const;
|
|
|
|
bool IsPublic(const clang::FileEntry* file) const;
|
|
|
|
// Parses a YAML/JSON file containing mapping directives of various types.
|
|
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 MappedInclude& map_to, IncludeVisibility 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 MappedInclude& 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 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.
|
|
void ExpandRegexes();
|
|
|
|
// Adds an entry to the given VisibilityMap, with error checking.
|
|
void MarkVisibility(VisibilityMap* map, const string& key,
|
|
IncludeVisibility visibility);
|
|
|
|
// Parse visibility from a string. Returns kUnusedVisibility if
|
|
// string is not recognized.
|
|
IncludeVisibility ParseVisibility(const string& visibility) const;
|
|
|
|
// Return the visibility of a given mapped include if known, else
|
|
// kUnusedVisibility.
|
|
IncludeVisibility GetVisibility(
|
|
const MappedInclude&,
|
|
IncludeVisibility default_value = kUnusedVisibility) 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
|
|
// map, filtering out private files.
|
|
vector<MappedInclude> GetPublicValues(const IncludeMap& m,
|
|
const string& key) const;
|
|
|
|
// Given an includer-pathname and includee-pathname, return the
|
|
// quoted-include of the includee, as written in the includer, or
|
|
// "" if it's not found for some reason.
|
|
string MaybeGetIncludeNameAsWritten(const string& includer_filepath,
|
|
const string& includee_filepath) const;
|
|
|
|
// Given a collection of MappedIncludes, and a path that might include them,
|
|
// choose the best quoted include form for each MappedInclude.
|
|
vector<string> BestQuotedIncludesForIncluder(
|
|
const vector<MappedInclude>&, const string& including_filepath) const;
|
|
|
|
// From symbols to includes.
|
|
IncludeMap symbol_include_map_;
|
|
|
|
// From quoted filepath patterns to includes, where a pattern can be
|
|
// either a quoted filepath (e.g. "foo/bar.h" or <a/b.h>) or @
|
|
// followed by a regular expression for matching a quoted filepath
|
|
// (e.g. @"foo/.*"). If key-value pair (pattern, headers) is in
|
|
// this map, it means that any header in 'headers' can be used to
|
|
// get symbols exported by a header matching 'pattern'.
|
|
IncludeMap filepath_include_map_;
|
|
|
|
// A map of all quoted-includes to whether they're public or private.
|
|
// Files whose visibility cannot be determined by this map nor the one
|
|
// below are assumed public.
|
|
VisibilityMap include_visibility_map_;
|
|
|
|
// A map of paths to whether they're public or private.
|
|
// Files whose visibility cannot be determined by this map nor the one
|
|
// above are assumed public.
|
|
// The include_visibility_map_ takes priority over this one.
|
|
VisibilityMap path_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.
|
|
map<string, set<string>> quoted_includes_to_quoted_includers_;
|
|
|
|
// Given the filepaths of an includer and includee, give the
|
|
// include-as-written (including <>'s or ""'s) that the includer
|
|
// used to refer to the includee. We use this to return includes as
|
|
// they were written in the source, when possible.
|
|
map<pair<string, string>, string>
|
|
includer_and_includee_to_include_as_written_;
|
|
|
|
// Maps from a quoted filepath pattern to the set of files that used
|
|
// a pragma declaring it as a friend. That is, if foo/bar/x.h has a
|
|
// line "// IWYU pragma: friend foo/bar/.*" then "x.h" will be a
|
|
// member of friend_to_headers_map_["@\"foo/bar/.*\""]. In a
|
|
// postprocessing step, files friend_to_headers_map_ will have
|
|
// regular expressions expanded, e.g. if foo/bar/x.cc is processed,
|
|
// friend_to_headers_map_["foo/bar/x.cc"] will be augmented with the
|
|
// contents of friend_to_headers_map_["@\"foo/bar/.*\""].
|
|
map<string, set<string>> friend_to_headers_map_;
|
|
|
|
// Make sure we don't do any non-const operations after finalizing.
|
|
bool has_called_finalize_added_include_lines_;
|
|
|
|
// Controls regex dialect to use for mappings.
|
|
RegexDialect regex_dialect;
|
|
}; // class IncludePicker
|
|
|
|
} // namespace include_what_you_use
|
|
|
|
#endif // INCLUDE_WHAT_YOU_USE_IWYU_INCLUDE_PICKER_H_
|