Issue 988 in include-what-you-use: [Feature request] Add "forward" mapping

0 views
Skip to first unread message

notifi...@include-what-you-use.org

unread,
Jan 3, 2022, 6:56:19 AM1/3/22
to include-wh...@googlegroups.com
New issue 988 by geimer: [Feature request] Add "forward" mapping
https://github.com/include-what-you-use/include-what-you-use/issues/988

The currently available `symbol` mapping already allows to map symbol _definitions_ to header files. However, in various use cases (see e.g., #530) it is desirable to use an include file for _forward declarations_ rather than explicitly repeating them all over the place. Unless I have missed something, this doesn't seem to be possible with the `symbol` mapping. Thus, I propose to implement a `forward` mapping type to also allow such kinds of mappings.

An alternative way of implementing this feature would be to introduce a `forward` visibility type for the `symbol` mapping, though I can't really judge which option makes more sense.


notifi...@include-what-you-use.org

unread,
Jan 6, 2022, 8:28:06 AM1/6/22
to include-wh...@googlegroups.com
Comment #0 on issue 988 by kimgr: [Feature request] Add "forward" mapping
https://github.com/include-what-you-use/include-what-you-use/issues/988

Yep, something like that would be nice.

I like the idea of a `forward` visibility, but my mind is too cloudy to play out exactly how it would work :-)

I'm mostly typing this up for myself, so I can reason about mappings, I'm not entirely sure this is how it works in practice...

For headers:
* Private-to-private mapping says: "From-header includes to-header, but they are both private"
* Private-to-public mapping says: "From-header is private, to-header is public."
* Public-to-public mapping says: "From-header includes to-header, and they are both public"
* Public-to-private mapping should never exist

The outcome of that is that given a suggested header A;
* if A is public and present, leave it
* if A is public and not present, is there a set of public-to-public mapping from A?
* for every to-header X mapped from A, is X present? If so, leave X.
* if not, suggest A
* if A is private, whether present or not
* if there is a private-to-public mapping from A to X, suggest X
* if not, is there a private-to-private mapping from A to Y? If yes, recurse with Y to see if we can find a public header.
* if no mapping available, suggest A as-is

For symbols, they are just folded into the mapping visibility structure for convenience. The from-visibility is ignored.
* to-private mapping says: "Symbol is defined in to-header, but it is private"
* to-public mapping says: "Symbol is defined in to-header and it is public."

In conjunction with header mappings this can resolve quite nicely. If a symbol is mapped to a private header and private header mapping eventually gives a public header, that strikes a nice balance between ease of generating automated mappings, e.g. `grep` for symbols and map them to their containing file, then `grep` for `#include` directives and generate header mappings. In practice it's not really that simple, of course.

So I wonder if it would be possible to smuggle a `forward-only` visibility into the unused from-visibility field of the symbol mapping... That would still allow to-private and to-public mappings for symbols, but resolution would have to start by deciding whether the symbol we're looking for is for a forward-declare use or a full use. Something like:

Given a used symbol A;
* if it's a forward-declare use, look up mappings for (A, forward-only) and perform resolution as before
* if it's a full use, look up mappings for (A, !forward-only) and perform resolution as before

So rather than tangling that into each mapping, it might make sense to have a separate database of forward-only mappings for symbols. External mapping files could still express it as `{ symbol: [ "std::cout", "forward-only", "<iosfwd>", "public" ] }`, for example, but they could be separated into a dedicated forward-only map when parsing/loading.

I don't know, it doesn't seem very principled, but maybe it doesn't have to be :).

It would be nice with a more structured definition language for mappings and externalization of pragmas. I've started thinking about that a few times, but never finished anything up.



notifi...@include-what-you-use.org

unread,
Jan 6, 2022, 8:30:10 AM1/6/22
to include-wh...@googlegroups.com
Comment #1 on issue 988 by kimgr: [Feature request] Add "forward" mapping
https://github.com/include-what-you-use/include-what-you-use/issues/988

Yep, something like that would be nice.

I like the idea of a `forward` visibility, but my mind is too cloudy to play out exactly how it would work :-)

I'm mostly typing this up for myself, so I can reason about mappings, I'm not entirely sure this is how it works in practice...

For headers:
* Private-to-private mapping says: "From-header includes to-header, but they are both private"
* Private-to-public mapping says: "From-header is private, to-header is public."
* Public-to-public mapping says: "From-header includes to-header, and they are both public"
* Public-to-private mapping should never exist

The outcome of that is that given a suggested header A;
* if A is public and present, leave it
* if A is public and not present, is there a set of public-to-public mapping from A?
* for every to-header X mapped from A, is X present? If so, leave X.
* if not, suggest A
* if A is private, whether present or not
* if there is a private-to-public mapping from A to X, suggest X
* if not, is there a private-to-private mapping from A to Y? If yes, recurse with Y to see if we can find a public header.
* if no mapping available, suggest A as-is

For symbols, they are just folded into the mapping visibility structure for convenience. The from-visibility is ignored.
* to-private mapping says: "Symbol is defined in to-header, but it is private"
* to-public mapping says: "Symbol is defined in to-header and it is public."

In conjunction with header mappings this can resolve quite nicely. If a symbol is mapped to a private header and private header mapping eventually gives a public header, we can follow the chain until we hit a public header.

That strikes a nice balance between mapping redundancy and ease of generating automated mappings, e.g. `grep` for symbols and map them to their containing file, then `grep` for `#include` directives and generate header mappings. In practice it's not really that simple, of course.

notifi...@include-what-you-use.org

unread,
Jan 10, 2022, 5:30:48 AM1/10/22
to include-wh...@googlegroups.com
Comment #1 on issue 988 by geimer: [Feature request] Add "forward" mapping
https://github.com/include-what-you-use/include-what-you-use/issues/988

From an outside perspective (i.e., not knowing anything about the implementation), what you wrote up makes sense to me.

If the visibility field is the way to go, maybe one could also consider replacing the `private` symbol visibility keyword by `definition` or similar, while deprecating but still supporting `private` as an alias for backward compatibility for a couple of releases (at least at the level of the mapping file format; what it resolves to internally during parsing is a different matter). Don't know how much refactoring this would require, though. Just an idea...


Reply all
Reply to author
Forward
0 new messages