Check if a location comes from begin/end of macro argument expansion

I'm struggling to find a way to detect if a given macro expanded
location is at the begin (or the end) of a macro argument expansion.

e.g. in this program

#define M(z) 0 + z + 0
#define N(x) M((x))
void h() {
  N(1);
}

I'd need to detect that source location of integer literal 1 is at the
begin (and the end) of expansion of argument x of macro N.

I think we should have enough info to do that (I've been able to reach a
similar result concerning macro expansion begin/end), but I'm still
unable to achieve always the correct final result.

I'd be very happy if Argyrios or another SourceManager guru could shed
some light on that.

Hi Abramo,

I'm struggling to find a way to detect if a given macro expanded
location is at the begin (or the end) of a macro argument expansion.

e.g. in this program

#define M(z) 0 + z + 0
#define N(x) M((x))
void h() {
N(1);
}

I'd need to detect that source location of integer literal 1 is at the
begin (and the end) of expansion of argument x of macro N.

I think we should have enough info to do that (I've been able to reach a
similar result concerning macro expansion begin/end), but I'm still
unable to achieve always the correct final result.

This is not simple/easy to do currently.

I think you can take advantage of the fact that the spelling location of a macro function expansion will always contain the parens, e.g. you'll be able to lex "MACRONAME ( .... )" (similar to how Preprocessor::ReadFunctionLikeMacroArgs does it) and get the token locations between the parens.
In your example you'll get the token locations for:
'N' '(' '1' ')'
and
'M' '(' '(' 'x' ')' ')'

you'll be able to lex the spelling locations and apply the offsets to the the actual locations in the expanded range of the macro contents.
After that you should be able to figure out if the location of '1' came from what token location inside the macro arguments. Also a bonus advantage will be being able to determine which exactly argument index it came from.

Did this make sense ?

-Argyrios

Hi Abramo,

I'm struggling to find a way to detect if a given macro expanded
location is at the begin (or the end) of a macro argument expansion.

e.g. in this program

#define M(z) 0 + z + 0
#define N(x) M((x))
void h() {
N(1);
}

I'd need to detect that source location of integer literal 1 is at the
begin (and the end) of expansion of argument x of macro N.

I think we should have enough info to do that (I've been able to reach a
similar result concerning macro expansion begin/end), but I'm still
unable to achieve always the correct final result.

This is not simple/easy to do currently.

I think you can take advantage of the fact that the spelling location of a macro function expansion will always contain the parens, e.g. you'll be able to lex "MACRONAME ( .... )" (similar to how Preprocessor::ReadFunctionLikeMacroArgs does it) and get the token locations between the parens.
In your example you'll get the token locations for:
'N' '(' '1' ')'
and
'M' '(' '(' 'x' ')' ')'

you'll be able to lex the spelling locations and apply the offsets to the the actual locations in the expanded range of the macro contents.
After that you should be able to figure out if the location of '1' came from what token location inside the macro arguments. Also a bonus advantage will be being able to determine which exactly argument index it came from.

Did this make sense ?

Perhaps I've found a simpler solution: looking for consecutive SLocEntry
for the same macro argument expansion (I can detect if they come from
the same macro argument expansion using immediate expansion start
location) I can know the range of expanded argument.

This is a dump of macro related SLocEntry (@ is an abbreviation for the
some big number prefix).

#define M(z) z
#define N(x) M((x))
void h() {
  N(M(1)+M(2));
}

4: macro @637-@643 exp:50-61 sloc:30 text:M((x)) N
5: macro @644-@645 exp:52-55 sloc:15 text:z M1
6: arg @646-@647 exp:@644-@644 sloc:54 text:1) M1.z
7: macro @648-@649 exp:57-60 sloc:15 text:z M2
8: arg @650-@651 exp:@648-@648 sloc:59 text:2) M2.z
9: arg @652-@653 exp:@640-@640 sloc:@646 text:1) N.x
10: arg @654-@655 exp:@640-@640 sloc:56 text:+M N.x
11: arg @656-@657 exp:@640-@640 sloc:@650 text:2) N.x
12: macro @658-@659 exp:@637-@642 sloc:15 text:z M
13: arg @660-@678 exp:@658-@658 sloc:@639 text:(x))|z|1)|z|2)|1)|+M|2) M.z
14: arg @679-@680 exp:@658-@658 sloc:@641 text:)) M.z

@660 @673 @675 @677 @679
  ( 1 + 2 )

From the SLocEntries above we can known that N.x expansion location

ranges is from @652 to @657, while M.z is from @660 to @680.

This might work? What do you think about?

Hi Abramo,

I'm struggling to find a way to detect if a given macro expanded
location is at the begin (or the end) of a macro argument expansion.

e.g. in this program

#define M(z) 0 + z + 0
#define N(x) M((x))
void h() {
N(1);
}

I'd need to detect that source location of integer literal 1 is at the
begin (and the end) of expansion of argument x of macro N.

I think we should have enough info to do that (I've been able to reach a
similar result concerning macro expansion begin/end), but I'm still
unable to achieve always the correct final result.

This is not simple/easy to do currently.

I think you can take advantage of the fact that the spelling location of a macro function expansion will always contain the parens, e.g. you'll be able to lex "MACRONAME ( .... )" (similar to how Preprocessor::ReadFunctionLikeMacroArgs does it) and get the token locations between the parens.
In your example you'll get the token locations for:
'N' '(' '1' ')'
and
'M' '(' '(' 'x' ')' ')'

you'll be able to lex the spelling locations and apply the offsets to the the actual locations in the expanded range of the macro contents.
After that you should be able to figure out if the location of '1' came from what token location inside the macro arguments. Also a bonus advantage will be being able to determine which exactly argument index it came from.

Did this make sense ?

Perhaps I've found a simpler solution: looking for consecutive SLocEntry
for the same macro argument expansion (I can detect if they come from
the same macro argument expansion using immediate expansion start
location) I can know the range of expanded argument.

This is a dump of macro related SLocEntry (@ is an abbreviation for the
some big number prefix).

#define M(z) z
#define N(x) M((x))
void h() {
N(M(1)+M(2));
}

4: macro @637-@643 exp:50-61 sloc:30 text:M((x)) N
5: macro @644-@645 exp:52-55 sloc:15 text:z M1
6: arg @646-@647 exp:@644-@644 sloc:54 text:1) M1.z
7: macro @648-@649 exp:57-60 sloc:15 text:z M2
8: arg @650-@651 exp:@648-@648 sloc:59 text:2) M2.z
9: arg @652-@653 exp:@640-@640 sloc:@646 text:1) N.x
10: arg @654-@655 exp:@640-@640 sloc:56 text:+M N.x
11: arg @656-@657 exp:@640-@640 sloc:@650 text:2) N.x
12: macro @658-@659 exp:@637-@642 sloc:15 text:z M
13: arg @660-@678 exp:@658-@658 sloc:@639 text:(x))|z|1)|z|2)|1)|+M|2) M.z
14: arg @679-@680 exp:@658-@658 sloc:@641 text:)) M.z

@660 @673 @675 @677 @679
( 1 + 2 )

From the SLocEntries above we can known that N.x expansion location
ranges is from @652 to @657, while M.z is from @660 to @680.

This might work? What do you think about?

Yes, I think this should work.