[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

Ted Kremenek kremenek at apple.com
Fri Dec 16 21:26:05 PST 2011


Author: kremenek
Date: Fri Dec 16 23:26:04 2011
New Revision: 146819

URL: http://llvm.org/viewvc/llvm-project?rev=146819&view=rev
Log:
Refactor 'TextDiagnostic' to have a parent class 'DiagnosticRenderer' which handles
the policy of how diagnostics are lowered/rendered, while TextDiagnostic handles
the actual pretty-printing.

This is a first part of reworking SerializedDiagnosticPrinter to use the same
inclusion-stack/macro-expansion logic as TextDiagnostic.

Added:
    cfe/trunk/include/clang/Frontend/DiagnosticRenderer.h
    cfe/trunk/lib/Frontend/DiagnosticRenderer.cpp
Modified:
    cfe/trunk/include/clang/Frontend/TextDiagnostic.h
    cfe/trunk/lib/Frontend/CMakeLists.txt
    cfe/trunk/lib/Frontend/TextDiagnostic.cpp

Added: cfe/trunk/include/clang/Frontend/DiagnosticRenderer.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/DiagnosticRenderer.h?rev=146819&view=auto
==============================================================================
--- cfe/trunk/include/clang/Frontend/DiagnosticRenderer.h (added)
+++ cfe/trunk/include/clang/Frontend/DiagnosticRenderer.h Fri Dec 16 23:26:04 2011
@@ -0,0 +1,123 @@
+//===--- DiagnosticRenderer.h - Diagnostic Pretty-Printing ------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a utility class that provides support for pretty-printing of
+// diagnostics. It is used to implement the different code paths which require
+// such functionality in a consistent way.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_
+#define LLVM_CLANG_FRONTEND_DIAGNOSTIC_RENDERER_H_
+
+#include "clang/Basic/Diagnostic.h"
+#include "clang/Basic/LLVM.h"
+#include "clang/Basic/SourceLocation.h"
+
+namespace clang {
+  class DiagnosticOptions;
+  class LangOptions;
+  class SourceManager;
+
+/// \brief Class to encapsulate the logic for formatting a diagnostic message.
+///  Actual "printing" logic is implemented by subclasses.
+///
+/// This class provides an interface for building and emitting
+/// diagnostic, including all of the macro backtraces, caret diagnostics, FixIt
+/// Hints, and code snippets. In the presence of macros this involves
+/// a recursive process, synthesizing notes for each macro expansion.
+///
+/// A brief worklist:
+/// FIXME: Sink the recursive printing of template instantiations into this
+/// class.
+class DiagnosticRenderer {
+protected:
+  const SourceManager &SM;
+  const LangOptions &LangOpts;
+  const DiagnosticOptions &DiagOpts;
+  
+  /// \brief The location of the previous diagnostic if known.
+  ///
+  /// This will be invalid in cases where there is no (known) previous
+  /// diagnostic location, or that location itself is invalid or comes from
+  /// a different source manager than SM.
+  SourceLocation LastLoc;
+  
+  /// \brief The location of the last include whose stack was printed if known.
+  ///
+  /// Same restriction as \see LastLoc essentially, but tracking include stack
+  /// root locations rather than diagnostic locations.
+  SourceLocation LastIncludeLoc;
+  
+  /// \brief The level of the last diagnostic emitted.
+  ///
+  /// The level of the last diagnostic emitted. Used to detect level changes
+  /// which change the amount of information displayed.
+  DiagnosticsEngine::Level LastLevel;
+
+  DiagnosticRenderer(const SourceManager &SM,
+                     const LangOptions &LangOpts,
+                     const DiagnosticOptions &DiagOpts);
+  
+  virtual ~DiagnosticRenderer();
+  
+  virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc,
+                                     DiagnosticsEngine::Level Level,
+                                     StringRef Message,
+                                     ArrayRef<CharSourceRange> Ranges,
+                                     const Diagnostic *Info) = 0;
+  
+  virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+                                 DiagnosticsEngine::Level Level,
+                                 ArrayRef<CharSourceRange> Ranges) = 0;
+  
+  virtual void emitBasicNote(StringRef Message) = 0;
+  
+  virtual void emitCodeContext(SourceLocation Loc,
+                               DiagnosticsEngine::Level Level,
+                               SmallVectorImpl<CharSourceRange>& Ranges,
+                               ArrayRef<FixItHint> Hints) = 0;
+  
+  virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc) = 0;
+  
+  virtual void beginDiagnostic(const Diagnostic *Info,
+                               DiagnosticsEngine::Level Level) {}
+  virtual void endDiagnostic(const Diagnostic *Info,
+                             DiagnosticsEngine::Level Level) {}
+
+  
+private:
+  void emitIncludeStack(SourceLocation Loc, DiagnosticsEngine::Level Level);
+  void emitIncludeStackRecursively(SourceLocation Loc);
+  void emitMacroExpansionsAndCarets(SourceLocation Loc,
+                                    DiagnosticsEngine::Level Level,
+                                    SmallVectorImpl<CharSourceRange>& Ranges,
+                                    ArrayRef<FixItHint> Hints,
+                                    unsigned &MacroDepth,
+                                    unsigned OnMacroInst = 0);
+public:
+  /// \brief Emit a diagnostic.
+  ///
+  /// This is the primary entry point for emitting diagnostic messages.
+  /// It handles formatting and rendering the message as well as any ancillary
+  /// information needed based on macros whose expansions impact the
+  /// diagnostic.
+  ///
+  /// \param Loc The location for this caret.
+  /// \param Level The level of the diagnostic to be emitted.
+  /// \param Message The diagnostic message to emit.
+  /// \param Ranges The underlined ranges for this code snippet.
+  /// \param FixItHints The FixIt hints active for this diagnostic.
+  void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
+                      StringRef Message, ArrayRef<CharSourceRange> Ranges,
+                      ArrayRef<FixItHint> FixItHints,
+                      const Diagnostic *Info = 0);
+};
+} // end clang namespace
+#endif

Modified: cfe/trunk/include/clang/Frontend/TextDiagnostic.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/TextDiagnostic.h?rev=146819&r1=146818&r2=146819&view=diff
==============================================================================
--- cfe/trunk/include/clang/Frontend/TextDiagnostic.h (original)
+++ cfe/trunk/include/clang/Frontend/TextDiagnostic.h Fri Dec 16 23:26:04 2011
@@ -16,14 +16,9 @@
 #ifndef LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_
 #define LLVM_CLANG_FRONTEND_TEXT_DIAGNOSTIC_H_
 
-#include "clang/Basic/Diagnostic.h"
-#include "clang/Basic/LLVM.h"
-#include "clang/Basic/SourceLocation.h"
+#include "clang/Frontend/DiagnosticRenderer.h"
 
 namespace clang {
-class DiagnosticOptions;
-class LangOptions;
-class SourceManager;
 
 /// \brief Class to encapsulate the logic for formatting and printing a textual
 /// diagnostic message.
@@ -37,34 +32,8 @@
 /// beautiful text diagnostics from any particular interfaces. The Clang
 /// DiagnosticClient is implemented through this class as is diagnostic
 /// printing coming out of libclang.
-///
-/// A brief worklist:
-/// FIXME: Sink the recursive printing of template instantiations into this
-/// class.
-class TextDiagnostic {
+class TextDiagnostic : public DiagnosticRenderer {
   raw_ostream &OS;
-  const SourceManager &SM;
-  const LangOptions &LangOpts;
-  const DiagnosticOptions &DiagOpts;
-
-  /// \brief The location of the previous diagnostic if known.
-  ///
-  /// This will be invalid in cases where there is no (known) previous
-  /// diagnostic location, or that location itself is invalid or comes from
-  /// a different source manager than SM.
-  SourceLocation LastLoc;
-
-  /// \brief The location of the last include whose stack was printed if known.
-  ///
-  /// Same restriction as \see LastLoc essentially, but tracking include stack
-  /// root locations rather than diagnostic locations.
-  SourceLocation LastIncludeLoc;
-
-  /// \brief The level of the last diagnostic emitted.
-  ///
-  /// The level of the last diagnostic emitted. Used to detect level changes
-  /// which change the amount of information displayed.
-  DiagnosticsEngine::Level LastLevel;
 
 public:
   TextDiagnostic(raw_ostream &OS,
@@ -72,22 +41,8 @@
                  const LangOptions &LangOpts,
                  const DiagnosticOptions &DiagOpts);
 
-  /// \brief Emit a textual diagnostic.
-  ///
-  /// This is the primary entry point for emitting textual diagnostic messages.
-  /// It handles formatting and printing the message as well as any ancillary
-  /// information needed based on macros whose expansions impact the
-  /// diagnostic.
-  ///
-  /// \param Loc The location for this caret.
-  /// \param Level The level of the diagnostic to be emitted.
-  /// \param Message The diagnostic message to emit.
-  /// \param Ranges The underlined ranges for this code snippet.
-  /// \param FixItHints The FixIt hints active for this diagnostic.
-  void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level,
-                      StringRef Message, ArrayRef<CharSourceRange> Ranges,
-                      ArrayRef<FixItHint> FixItHints);
-
+  virtual ~TextDiagnostic();
+  
   /// \brief Print the diagonstic level to a raw_ostream.
   ///
   /// This is a static helper that handles colorizing the level and formatting
@@ -121,18 +76,29 @@
                                      unsigned CurrentColumn, unsigned Columns,
                                      bool ShowColors);
 
+protected:
+  virtual void emitDiagnosticMessage(SourceLocation Loc,PresumedLoc PLoc,
+                                     DiagnosticsEngine::Level Level,
+                                     StringRef Message,
+                                     ArrayRef<CharSourceRange> Ranges,
+                                     const Diagnostic *Info);
+
+  virtual void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
+                                 DiagnosticsEngine::Level Level,
+                                 ArrayRef<CharSourceRange> Ranges);
+  
+  virtual void emitCodeContext(SourceLocation Loc,
+                               DiagnosticsEngine::Level Level,
+                               SmallVectorImpl<CharSourceRange>& Ranges,
+                               ArrayRef<FixItHint> Hints) {
+    emitSnippetAndCaret(Loc, Level, Ranges, Hints);
+  }
+  
+  virtual void emitBasicNote(StringRef Message);
+  
+  virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc);
+
 private:
-  void emitIncludeStack(SourceLocation Loc, DiagnosticsEngine::Level Level);
-  void emitIncludeStackRecursively(SourceLocation Loc);
-  void emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc,
-                         DiagnosticsEngine::Level Level,
-                         ArrayRef<CharSourceRange> Ranges);
-  void emitMacroExpansionsAndCarets(SourceLocation Loc,
-                                    DiagnosticsEngine::Level Level,
-                                    SmallVectorImpl<CharSourceRange>& Ranges,
-                                    ArrayRef<FixItHint> Hints,
-                                    unsigned &MacroDepth,
-                                    unsigned OnMacroInst = 0);
   void emitSnippetAndCaret(SourceLocation Loc, DiagnosticsEngine::Level Level,
                            SmallVectorImpl<CharSourceRange>& Ranges,
                            ArrayRef<FixItHint> Hints);

Modified: cfe/trunk/lib/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=146819&r1=146818&r2=146819&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/lib/Frontend/CMakeLists.txt Fri Dec 16 23:26:04 2011
@@ -18,6 +18,7 @@
   CompilerInvocation.cpp
   CreateInvocationFromCommandLine.cpp
   DependencyFile.cpp
+  DiagnosticRenderer.cpp
   FrontendAction.cpp
   FrontendActions.cpp
   FrontendOptions.cpp

Added: cfe/trunk/lib/Frontend/DiagnosticRenderer.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/DiagnosticRenderer.cpp?rev=146819&view=auto
==============================================================================
--- cfe/trunk/lib/Frontend/DiagnosticRenderer.cpp (added)
+++ cfe/trunk/lib/Frontend/DiagnosticRenderer.cpp Fri Dec 16 23:26:04 2011
@@ -0,0 +1,297 @@
+//===--- DiagnosticRenderer.cpp - Diagnostic Pretty-Printing --------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Frontend/DiagnosticRenderer.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Frontend/DiagnosticOptions.h"
+#include "clang/Lex/Lexer.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/ADT/SmallString.h"
+#include <algorithm>
+using namespace clang;
+
+/// 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);
+}
+
+DiagnosticRenderer::DiagnosticRenderer(const SourceManager &SM,
+                                       const LangOptions &LangOpts,
+                                       const DiagnosticOptions &DiagOpts)
+: SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
+
+DiagnosticRenderer::~DiagnosticRenderer() {}
+
+
+void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc,
+                                        DiagnosticsEngine::Level Level,
+                                        StringRef Message,
+                                        ArrayRef<CharSourceRange> Ranges,
+                                        ArrayRef<FixItHint> FixItHints,
+                                        const Diagnostic *Info) {
+  
+  beginDiagnostic(Info, Level);
+  
+  PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc);
+  
+  // First, if this diagnostic is not in the main file, print out the
+  // "included from" lines.
+  emitIncludeStack(PLoc.getIncludeLoc(), Level);
+  
+  // Next, emit the actual diagnostic message.
+  emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, Info);
+  
+  // Only recurse if we have a valid location.
+  if (Loc.isValid()) {
+    // Get the ranges into a local array we can hack on.
+    SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
+                                                   Ranges.end());
+    
+    for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(),
+         E = FixItHints.end();
+         I != E; ++I)
+      if (I->RemoveRange.isValid())
+        MutableRanges.push_back(I->RemoveRange);
+    
+    unsigned MacroDepth = 0;
+    emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints,
+                                 MacroDepth);
+  }
+  
+  LastLoc = Loc;
+  LastLevel = Level;
+  
+  endDiagnostic(Info, Level);
+}
+
+/// \brief Prints an include stack when appropriate for a particular
+/// diagnostic level and location.
+///
+/// This routine handles all the logic of suppressing particular include
+/// stacks (such as those for notes) and duplicate include stacks when
+/// repeated warnings occur within the same file. It also handles the logic
+/// of customizing the formatting and display of the include stack.
+///
+/// \param Level The diagnostic level of the message this stack pertains to.
+/// \param Loc   The include location of the current file (not the diagnostic
+///              location).
+void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc,
+                                          DiagnosticsEngine::Level Level) {
+  // Skip redundant include stacks altogether.
+  if (LastIncludeLoc == Loc)
+    return;
+  LastIncludeLoc = Loc;
+  
+  if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
+    return;
+  
+  emitIncludeStackRecursively(Loc);
+}
+
+/// \brief Helper to recursivly walk up the include stack and print each layer
+/// on the way back down.
+void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc) {
+  if (Loc.isInvalid())
+    return;
+  
+  PresumedLoc PLoc = SM.getPresumedLoc(Loc);
+  if (PLoc.isInvalid())
+    return;
+  
+  // Emit the other include frames first.
+  emitIncludeStackRecursively(PLoc.getIncludeLoc());
+  
+  // Emit the inclusion text/note.
+  emitIncludeLocation(Loc, PLoc);
+}
+
+/// \brief Recursively emit notes for each macro expansion and caret
+/// diagnostics where appropriate.
+///
+/// Walks up the macro expansion stack printing expansion notes, the code
+/// snippet, caret, underlines and FixItHint display as appropriate at each
+/// level.
+///
+/// \param Loc The location for this caret.
+/// \param Level The diagnostic level currently being emitted.
+/// \param Ranges The underlined ranges for this code snippet.
+/// \param Hints The FixIt hints active for this diagnostic.
+/// \param MacroSkipEnd The depth to stop skipping macro expansions.
+/// \param OnMacroInst The current depth of the macro expansion stack.
+void DiagnosticRenderer::emitMacroExpansionsAndCarets(
+       SourceLocation Loc,
+       DiagnosticsEngine::Level Level,
+       SmallVectorImpl<CharSourceRange>& Ranges,
+       ArrayRef<FixItHint> Hints,
+       unsigned &MacroDepth,
+       unsigned OnMacroInst)
+{
+  assert(!Loc.isInvalid() && "must have a valid source location here");
+  
+  // If this is a file source location, directly emit the source snippet and
+  // caret line. Also record the macro depth reached.
+  if (Loc.isFileID()) {
+    assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
+    MacroDepth = OnMacroInst;
+    emitCodeContext(Loc, Level, Ranges, Hints);
+    return;
+  }
+  // Otherwise recurse through each macro expansion layer.
+  
+  // When processing macros, skip over the expansions leading up to
+  // a macro argument, and trace the argument's expansion stack instead.
+  Loc = skipToMacroArgExpansion(SM, Loc);
+  
+  SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc);
+  
+  // FIXME: Map ranges?
+  emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, MacroDepth,
+                               OnMacroInst + 1);
+  
+  // Save the original location so we can find the spelling of the macro call.
+  SourceLocation MacroLoc = Loc;
+  
+  // Map the location.
+  Loc = getImmediateMacroCalleeLoc(SM, Loc);
+  
+  unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
+  if (MacroDepth > DiagOpts.MacroBacktraceLimit) {
+    MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
+    DiagOpts.MacroBacktraceLimit % 2;
+    MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
+  }
+  
+  // Whether to suppress printing this macro expansion.
+  bool Suppressed = (OnMacroInst >= MacroSkipStart &&
+                     OnMacroInst < MacroSkipEnd);
+  
+  // Map the ranges.
+  for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
+       E = Ranges.end();
+       I != E; ++I) {
+    SourceLocation Start = I->getBegin(), End = I->getEnd();
+    if (Start.isMacroID())
+      I->setBegin(getImmediateMacroCalleeLoc(SM, Start));
+    if (End.isMacroID())
+      I->setEnd(getImmediateMacroCalleeLoc(SM, End));
+  }
+  
+  if (Suppressed) {
+    // Tell the user that we've skipped contexts.
+    if (OnMacroInst == MacroSkipStart) {
+      llvm::SmallString<200> MessageStorage;
+      llvm::raw_svector_ostream Message(MessageStorage);
+      Message << "(skipping " << (MacroSkipEnd - MacroSkipStart)
+              << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "
+                 "see all)";
+      emitBasicNote(Message.str());      
+    }
+    return;
+  }
+  
+  llvm::SmallString<100> MessageStorage;
+  llvm::raw_svector_ostream Message(MessageStorage);
+  Message << "expanded from macro '"
+          << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
+  emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
+                 Message.str(),
+                 Ranges, ArrayRef<FixItHint>());
+}
+

Modified: cfe/trunk/lib/Frontend/TextDiagnostic.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/TextDiagnostic.cpp?rev=146819&r1=146818&r2=146819&view=diff
==============================================================================
--- cfe/trunk/lib/Frontend/TextDiagnostic.cpp (original)
+++ cfe/trunk/lib/Frontend/TextDiagnostic.cpp Fri Dec 16 23:26:04 2011
@@ -174,70 +174,6 @@
   }
 }
 
-/// 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);
-}
-
-/// 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);
-}
-
 /// \brief Skip over whitespace in the string, starting at the given
 /// index.
 ///
@@ -389,85 +325,33 @@
   return Wrapped;
 }
 
-/// \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);
-}
-
 TextDiagnostic::TextDiagnostic(raw_ostream &OS,
                                const SourceManager &SM,
                                const LangOptions &LangOpts,
                                const DiagnosticOptions &DiagOpts)
-  : OS(OS), SM(SM), LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {
-}
+  : DiagnosticRenderer(SM, LangOpts, DiagOpts), OS(OS) {}
 
-void TextDiagnostic::emitDiagnostic(SourceLocation Loc,
-                                    DiagnosticsEngine::Level Level,
-                                    StringRef Message,
-                                    ArrayRef<CharSourceRange> Ranges,
-                                    ArrayRef<FixItHint> FixItHints) {
-  PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc);
-
-  // First, if this diagnostic is not in the main file, print out the
-  // "included from" lines.
-  emitIncludeStack(PLoc.getIncludeLoc(), Level);
+TextDiagnostic::~TextDiagnostic() {}
 
+void
+TextDiagnostic::emitDiagnosticMessage(SourceLocation Loc,
+                                      PresumedLoc PLoc,
+                                      DiagnosticsEngine::Level Level,
+                                      StringRef Message,
+                                      ArrayRef<clang::CharSourceRange> Ranges,
+                                      const Diagnostic *Info) {
   uint64_t StartOfLocationInfo = OS.tell();
 
-  // Next emit the location of this particular diagnostic.
+  // Emit the location of this particular diagnostic.
   emitDiagnosticLoc(Loc, PLoc, Level, Ranges);
-
+  
   if (DiagOpts.ShowColors)
     OS.resetColor();
-
+  
   printDiagnosticLevel(OS, Level, DiagOpts.ShowColors);
   printDiagnosticMessage(OS, Level, Message,
                          OS.tell() - StartOfLocationInfo,
                          DiagOpts.MessageLength, DiagOpts.ShowColors);
-
-  // Only recurse if we have a valid location.
-  if (Loc.isValid()) {
-    // Get the ranges into a local array we can hack on.
-    SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(),
-                                                   Ranges.end());
-
-    for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(),
-                                             E = FixItHints.end();
-         I != E; ++I)
-      if (I->RemoveRange.isValid())
-        MutableRanges.push_back(I->RemoveRange);
-
-    unsigned MacroDepth = 0;
-    emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints,
-                                 MacroDepth);
-  }
-
-  LastLoc = Loc;
-  LastLevel = Level;
 }
 
 /*static*/ void
@@ -525,50 +409,6 @@
   OS << '\n';
 }
 
-/// \brief Prints an include stack when appropriate for a particular
-/// diagnostic level and location.
-///
-/// This routine handles all the logic of suppressing particular include
-/// stacks (such as those for notes) and duplicate include stacks when
-/// repeated warnings occur within the same file. It also handles the logic
-/// of customizing the formatting and display of the include stack.
-///
-/// \param Level The diagnostic level of the message this stack pertains to.
-/// \param Loc   The include location of the current file (not the diagnostic
-///              location).
-void TextDiagnostic::emitIncludeStack(SourceLocation Loc,
-                                      DiagnosticsEngine::Level Level) {
-  // Skip redundant include stacks altogether.
-  if (LastIncludeLoc == Loc)
-    return;
-  LastIncludeLoc = Loc;
-
-  if (!DiagOpts.ShowNoteIncludeStack && Level == DiagnosticsEngine::Note)
-    return;
-
-  emitIncludeStackRecursively(Loc);
-}
-
-/// \brief Helper to recursivly walk up the include stack and print each layer
-/// on the way back down.
-void TextDiagnostic::emitIncludeStackRecursively(SourceLocation Loc) {
-  if (Loc.isInvalid())
-    return;
-
-  PresumedLoc PLoc = SM.getPresumedLoc(Loc);
-  if (PLoc.isInvalid())
-    return;
-
-  // Emit the other include frames first.
-  emitIncludeStackRecursively(PLoc.getIncludeLoc());
-
-  if (DiagOpts.ShowLocation)
-    OS << "In file included from " << PLoc.getFilename()
-       << ':' << PLoc.getLine() << ":\n";
-  else
-    OS << "In included file:\n";
-}
-
 /// \brief Print out the file/line/column information and include trace.
 ///
 /// This method handlen the emission of the diagnostic location information.
@@ -676,95 +516,19 @@
   OS << ' ';
 }
 
-/// \brief Recursively emit notes for each macro expansion and caret
-/// diagnostics where appropriate.
-///
-/// Walks up the macro expansion stack printing expansion notes, the code
-/// snippet, caret, underlines and FixItHint display as appropriate at each
-/// level.
-///
-/// \param Loc The location for this caret.
-/// \param Level The diagnostic level currently being emitted.
-/// \param Ranges The underlined ranges for this code snippet.
-/// \param Hints The FixIt hints active for this diagnostic.
-/// \param MacroSkipEnd The depth to stop skipping macro expansions.
-/// \param OnMacroInst The current depth of the macro expansion stack.
-void TextDiagnostic::emitMacroExpansionsAndCarets(
-    SourceLocation Loc,
-    DiagnosticsEngine::Level Level,
-    SmallVectorImpl<CharSourceRange>& Ranges,
-    ArrayRef<FixItHint> Hints,
-    unsigned &MacroDepth,
-    unsigned OnMacroInst) {
-  assert(!Loc.isInvalid() && "must have a valid source location here");
-
-  // If this is a file source location, directly emit the source snippet and
-  // caret line. Also record the macro depth reached.
-  if (Loc.isFileID()) {
-    assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!");
-    MacroDepth = OnMacroInst;
-    emitSnippetAndCaret(Loc, Level, Ranges, Hints);
-    return;
-  }
-  // Otherwise recurse through each macro expansion layer.
-
-  // When processing macros, skip over the expansions leading up to
-  // a macro argument, and trace the argument's expansion stack instead.
-  Loc = skipToMacroArgExpansion(SM, Loc);
-
-  SourceLocation OneLevelUp = getImmediateMacroCallerLoc(SM, Loc);
-
-  // FIXME: Map ranges?
-  emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, MacroDepth,
-                               OnMacroInst + 1);
-
-  // Save the original location so we can find the spelling of the macro call.
-  SourceLocation MacroLoc = Loc;
-
-  // Map the location.
-  Loc = getImmediateMacroCalleeLoc(SM, Loc);
-
-  unsigned MacroSkipStart = 0, MacroSkipEnd = 0;
-  if (MacroDepth > DiagOpts.MacroBacktraceLimit) {
-    MacroSkipStart = DiagOpts.MacroBacktraceLimit / 2 +
-      DiagOpts.MacroBacktraceLimit % 2;
-    MacroSkipEnd = MacroDepth - DiagOpts.MacroBacktraceLimit / 2;
-  }
-
-  // Whether to suppress printing this macro expansion.
-  bool Suppressed = (OnMacroInst >= MacroSkipStart &&
-                     OnMacroInst < MacroSkipEnd);
-
-  // Map the ranges.
-  for (SmallVectorImpl<CharSourceRange>::iterator I = Ranges.begin(),
-                                                  E = Ranges.end();
-       I != E; ++I) {
-    SourceLocation Start = I->getBegin(), End = I->getEnd();
-    if (Start.isMacroID())
-      I->setBegin(getImmediateMacroCalleeLoc(SM, Start));
-    if (End.isMacroID())
-      I->setEnd(getImmediateMacroCalleeLoc(SM, End));
-  }
-
-  if (Suppressed) {
-    // Tell the user that we've skipped contexts.
-    if (OnMacroInst == MacroSkipStart) {
-      // FIXME: Emit this as a real note diagnostic.
-      // FIXME: Format an actual diagnostic rather than a hard coded string.
-      OS << "note: (skipping " << (MacroSkipEnd - MacroSkipStart)
-         << " expansions in backtrace; use -fmacro-backtrace-limit=0 to see "
-            "all)\n";
-    }
-    return;
-  }
+void TextDiagnostic::emitBasicNote(StringRef Message) {
+  // FIXME: Emit this as a real note diagnostic.
+  // FIXME: Format an actual diagnostic rather than a hard coded string.
+  OS << "note: " << Message << "\n";
+}
 
-  llvm::SmallString<100> MessageStorage;
-  llvm::raw_svector_ostream Message(MessageStorage);
-  Message << "expanded from macro '"
-          << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'";
-  emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note,
-                 Message.str(),
-                 Ranges, ArrayRef<FixItHint>());
+void TextDiagnostic::emitIncludeLocation(SourceLocation Loc,
+                                         PresumedLoc PLoc) {
+  if (DiagOpts.ShowLocation)
+    OS << "In file included from " << PLoc.getFilename() << ':'
+       << PLoc.getLine() << ":\n";
+  else
+    OS << "In included file:\n"; 
 }
 
 /// \brief Emit a code snippet and caret line.





More information about the cfe-commits mailing list