[cfe-commits] r146819 - in /cfe/trunk: include/clang/Frontend/DiagnosticRenderer.h include/clang/Frontend/TextDiagnostic.h lib/Frontend/CMakeLists.txt lib/Frontend/DiagnosticRenderer.cpp lib/Frontend/TextDiagnostic.cpp

Matt Beaumont-Gay matthewbg at google.com
Thu May 24 16:01:24 PDT 2012


Apologies for the necrothread...

> +/// Look through spelling locations for a macro argument expansion, and
> +/// if found skip to it so that we can trace the argument rather than the macros
> +/// in which that argument is used. If no macro argument expansion is found,
> +/// don't skip anything and return the starting location.
> +static SourceLocation skipToMacroArgExpansion(const SourceManager &SM,
> +                                              SourceLocation StartLoc) {
> +  for (SourceLocation L = StartLoc; L.isMacroID();
> +       L = SM.getImmediateSpellingLoc(L)) {
> +    if (SM.isMacroArgExpansion(L))
> +      return L;
> +  }
> +
> +  // Otherwise just return initial location, there's nothing to skip.
> +  return StartLoc;
> +}
> +
> +/// Gets the location of the immediate macro caller, one level up the stack
> +/// toward the initial macro typed into the source.
> +static SourceLocation getImmediateMacroCallerLoc(const SourceManager &SM,
> +                                                 SourceLocation Loc) {
> +  if (!Loc.isMacroID()) return Loc;
> +
> +  // When we have the location of (part of) an expanded parameter, its spelling
> +  // location points to the argument as typed into the macro call, and
> +  // therefore is used to locate the macro caller.
> +  if (SM.isMacroArgExpansion(Loc))
> +    return SM.getImmediateSpellingLoc(Loc);
> +
> +  // Otherwise, the caller of the macro is located where this macro is
> +  // expanded (while the spelling is part of the macro definition).
> +  return SM.getImmediateExpansionRange(Loc).first;
> +}
> +
> +/// Gets the location of the immediate macro callee, one level down the stack
> +/// toward the leaf macro.
> +static SourceLocation getImmediateMacroCalleeLoc(const SourceManager &SM,
> +                                                 SourceLocation Loc) {
> +  if (!Loc.isMacroID()) return Loc;
> +
> +  // When we have the location of (part of) an expanded parameter, its
> +  // expansion location points to the unexpanded paramater reference within
> +  // the macro definition (or callee).
> +  if (SM.isMacroArgExpansion(Loc))
> +    return SM.getImmediateExpansionRange(Loc).first;
> +
> +  // Otherwise, the callee of the macro is located where this location was
> +  // spelled inside the macro definition.
> +  return SM.getImmediateSpellingLoc(Loc);
> +}
> +
> +/// \brief Retrieve the name of the immediate macro expansion.
> +///
> +/// This routine starts from a source location, and finds the name of the macro
> +/// responsible for its immediate expansion. It looks through any intervening
> +/// macro argument expansions to compute this. It returns a StringRef which
> +/// refers to the SourceManager-owned buffer of the source where that macro
> +/// name is spelled. Thus, the result shouldn't out-live that SourceManager.
> +///
> +static StringRef getImmediateMacroName(SourceLocation Loc,
> +                                       const SourceManager &SM,
> +                                       const LangOptions &LangOpts) {
> +  assert(Loc.isMacroID() && "Only reasonble to call this on macros");
> +  // Walk past macro argument expanions.
> +  while (SM.isMacroArgExpansion(Loc))
> +    Loc = SM.getImmediateExpansionRange(Loc).first;
> +
> +  // Find the spelling location of the start of the non-argument expansion
> +  // range. This is where the macro name was spelled in order to begin
> +  // expanding this macro.
> +  Loc = SM.getSpellingLoc(SM.getImmediateExpansionRange(Loc).first);
> +
> +  // Dig out the buffer where the macro name was spelled and the extents of the
> +  // name so that we can render it into the expansion note.
> +  std::pair<FileID, unsigned> ExpansionInfo = SM.getDecomposedLoc(Loc);
> +  unsigned MacroTokenLength = Lexer::MeasureTokenLength(Loc, SM, LangOpts);
> +  StringRef ExpansionBuffer = SM.getBufferData(ExpansionInfo.first);
> +  return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
> +}
> +
> +/// Get the presumed location of a diagnostic message. This computes the
> +/// presumed location for the top of any macro backtrace when present.
> +static PresumedLoc getDiagnosticPresumedLoc(const SourceManager &SM,
> +                                            SourceLocation Loc) {
> +  // This is a condensed form of the algorithm used by emitCaretDiagnostic to
> +  // walk to the top of the macro call stack.
> +  while (Loc.isMacroID()) {
> +    Loc = skipToMacroArgExpansion(SM, Loc);
> +    Loc = getImmediateMacroCallerLoc(SM, Loc);
> +  }
> +
> +  return SM.getPresumedLoc(Loc);
> +}

I've recently found myself needing this machinery in a slightly
different context (hacking on a specialized diagnostic client). It
seems like SourceManager might be a natural place for these functions
to be made available to other users. I'm thinking that
getDiagnosticPresumedLoc would be the only new public method, though
possibly under a slightly different name (bikeshed hues welcome). Any
objections to such a refactoring?

-Matt




More information about the cfe-commits mailing list