[cfe-dev] SourceLocation -> MacroDefinition(Record?)
Kim Gräsman
kim.grasman at gmail.com
Tue Jul 14 13:52:12 PDT 2015
On Tue, May 19, 2015 at 10:15 PM, Kim Gräsman <kim.grasman at gmail.com> wrote:
>
> I have a Decl and a location where it's used.
>
> If that location is in a macro, we want to attribute the use to the
> file containing the macro, unless
> a) there is a prior forward-declaration of the Decl in the macro file
> b) the use-location points to a macro-argument
>
> So for example:
>
> --
> // macro.h
>
> // attribute std::max to macro.h, because it's an implementation
> // detail of YET_ANOTHER_MAX.
> #include <algorithm>
> #define YET_ANOTHER_MAX(x, y) std::max(x, y)
>
> // attribute Thing to callers because it's forward-declared,
> // and we use that as a marker that we want to defer responsibility.
> class Thing;
> #define DECLARE_THING(name) Thing name;
>
> // attribute x to callers, because it's a macro argument,
> // and they're responsible for what they pass in.
> #define LENGTH_OF(x) (sizeof(x) / sizeof(*x))
> --
OK, so I've come up with this snippet that appears to do what I want:
--
SourceLocation GetUseLocationForMacroExpansion(SourceLocation use_loc,
const Decl* used_decl) {
CHECK_(IsInMacro(use_loc) && "Unexpected non-macro-expansion call");
SourceManager& SM = *GlobalSourceManager();
SourceLocation caller_loc = GetInstantiationLoc(use_loc);
if (StartsWith(PrintableLoc(GetSpellingLoc(use_loc)), "<scratch ")) {
// In scratch space; caller is responsible.
return caller_loc;
} else if (IsForwardDeclaredInSameFile(used_decl, use_loc)) {
// There's a forward-declaration in the macro file; force responsibility
// onto caller.
return caller_loc;
} else if (SM.isMacroArgExpansion(use_loc)) {
// use_loc might be pointing directly to a macro argument, ask the
// source manager if that's the case.
// If so, it's the callers responsibility
return caller_loc;
} else {
// use_loc might be pointing to an expression, e.g. sizeof(*x) --
// use the lexer to dig out 'x'
llvm::StringRef macro_name =
compiler()->getPreprocessor().getImmediateMacroName(use_loc);
const IdentifierInfo* ii =
compiler()->getPreprocessor().getIdentifierInfo(macro_name);
const MacroInfo* mi = compiler()->getPreprocessor().getMacroInfo(ii);
// FindNextIdentifier uses the raw lexer to find the nearest
identifier token
// between use_loc and the end of the macro definition.
SourceLocation eom = mi->getDefinitionEndLoc();
string identifier =
FindNextIdentifier(GetSpellingLoc(use_loc), eom, DefaultDataGetter());
for (MacroInfo::arg_iterator i = mi->arg_begin(); i != mi->arg_end(); ++i) {
if ((*i)->getName() == identifier)
return caller_loc;
}
}
return use_loc;
}
--
I'm not entirely satisified with the last leg, where I try to figure
out if a macro-argument is part of an expression at the use-location.
For example, this:
#define ADDRESS_OF(x) &x
will have use_loc pointing to the ampersand, not the x identifier.
I feel like I'm bouncing back and forth between strings and structure
to get what I want. I'm guessing there's a cleaner way?
Thanks,
- Kim
More information about the cfe-dev
mailing list