[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