Introduce a new PresumedLoc class to represent the concept of a location
as reported to the user and as manipulated by #line.  This is what __FILE__,
__INCLUDE_LEVEL__, diagnostics and other things should follow (but not 
dependency generation!).  

This patch also includes several cleanups along the way: 

- SourceLocation now has a dump method, and several other places 
  that did similar things now use it.
- I cleaned up some code in AnalysisConsumer, but it should probably be
  simplified further now that NamedDecl is better.
- TextDiagnosticPrinter is now simplified and cleaned up a bit.

This patch is a prerequisite for #line, but does not actually provide 
any #line functionality.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@63098 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp
index 0a7de35..83313ed 100644
--- a/lib/AST/StmtDumper.cpp
+++ b/lib/AST/StmtDumper.cpp
@@ -153,21 +153,26 @@
 
 void StmtDumper::DumpLocation(SourceLocation Loc) {
   SourceLocation SpellingLoc = SM->getSpellingLoc(Loc);
+  
+  if (SpellingLoc.isInvalid()) {
+    fprintf(stderr, "<invalid sloc>");
+    return;
+  }
 
   // The general format we print out is filename:line:col, but we drop pieces
   // that haven't changed since the last loc printed.
-  const char *Filename = SM->getSourceName(SpellingLoc);
-  unsigned LineNo = SM->getLineNumber(SpellingLoc);
-  unsigned ColNo = SM->getColumnNumber(SpellingLoc);
-  if (strcmp(Filename, LastLocFilename) != 0) {
-    fprintf(stderr, "%s:%u:%u", Filename, LineNo, ColNo);
-    LastLocFilename = Filename;
-    LastLocLine = LineNo;
-  } else if (LineNo != LastLocLine) {
-    fprintf(stderr, "line:%u:%u", LineNo, ColNo);
-    LastLocLine = LineNo;
+  PresumedLoc PLoc = SM->getPresumedLoc(SpellingLoc);
+
+  if (strcmp(PLoc.getFilename(), LastLocFilename) != 0) {
+    fprintf(stderr, "%s:%u:%u", PLoc.getFilename(), PLoc.getLine(),
+            PLoc.getColumn());
+    LastLocFilename = PLoc.getFilename();
+    LastLocLine = PLoc.getLine();
+  } else if (PLoc.getLine() != LastLocLine) {
+    fprintf(stderr, "line:%u:%u", PLoc.getLine(), PLoc.getColumn());
+    LastLocLine = PLoc.getLine();
   } else {
-    fprintf(stderr, "col:%u", ColNo);
+    fprintf(stderr, "col:%u", PLoc.getColumn());
   }
 }
 
diff --git a/lib/Analysis/LiveVariables.cpp b/lib/Analysis/LiveVariables.cpp
index ac0aa9b..4c86d44 100644
--- a/lib/Analysis/LiveVariables.cpp
+++ b/lib/Analysis/LiveVariables.cpp
@@ -358,13 +358,9 @@
   for (AnalysisDataTy::decl_iterator I = AD.begin_decl(),
                                      E = AD.end_decl(); I!=E; ++I)
     if (V.getDeclBit(I->second)) {      
-      SourceLocation SpellingLoc = SM.getSpellingLoc(I->first->getLocation());
-    
-      fprintf(stderr, "  %s <%s:%u:%u>\n", 
-              I->first->getIdentifier()->getName(),
-              SM.getSourceName(SpellingLoc),
-              SM.getLineNumber(SpellingLoc),
-              SM.getColumnNumber(SpellingLoc));
+      fprintf(stderr, "  %s <", I->first->getIdentifier()->getName());
+      I->first->getLocation().dump(SM);
+      fprintf(stderr, ">\n");
     }
 }                                  
 
diff --git a/lib/Basic/SourceLocation.cpp b/lib/Basic/SourceLocation.cpp
index f0c8274..5d48472 100644
--- a/lib/Basic/SourceLocation.cpp
+++ b/lib/Basic/SourceLocation.cpp
@@ -26,6 +26,29 @@
   return SourceLocation::getFromRawEncoding(D.ReadInt());   
 }
 
+void SourceLocation::dump(const SourceManager &SM) const {
+  if (!isValid()) {
+    fprintf(stderr, "<invalid loc>");
+    return;
+  }
+  
+  if (isFileID()) {
+    PresumedLoc PLoc = SM.getPresumedLoc(*this);
+    
+    // The instantiation and spelling pos is identical for file locs.
+    fprintf(stderr, "%s:%d:%d",
+            PLoc.getFilename(), PLoc.getLine(), PLoc.getColumn());
+    return;
+  }
+  
+  SM.getInstantiationLoc(*this).dump(SM);
+  
+  fprintf(stderr, " <Spelling=");
+  SM.getSpellingLoc(*this).dump(SM);
+  fprintf(stderr, ">");
+}
+
+
 void SourceRange::Emit(llvm::Serializer& S) const {
   B.Emit(S);
   E.Emit(S);
@@ -53,11 +76,6 @@
   return FullSourceLoc(SrcMgr->getSpellingLoc(*this), *SrcMgr);
 }
 
-FullSourceLoc FullSourceLoc::getIncludeLoc() const {
-  assert(isValid());
-  return FullSourceLoc(SrcMgr->getIncludeLoc(*this), *SrcMgr);
-}
-
 unsigned FullSourceLoc::getLineNumber() const {
   assert(isValid());
   return SrcMgr->getLineNumber(*this);
@@ -89,11 +107,6 @@
   return SrcMgr->getSpellingColumnNumber(*this);
 }
 
-const char* FullSourceLoc::getSourceName() const {
-  assert(isValid());
-  return SrcMgr->getSourceName(*this);
-}
-
 bool FullSourceLoc::isInSystemHeader() const {
   assert(isValid());
   return SrcMgr->isInSystemHeader(*this);
@@ -109,22 +122,3 @@
   return SrcMgr->getBuffer(SrcMgr->getFileID(*this));
 }
 
-void FullSourceLoc::dump() const {
-  if (!isValid()) {
-    fprintf(stderr, "Invalid Loc\n");
-    return;
-  }
-  
-  if (isFileID()) {
-    // The instantiation and spelling pos is identical for file locs.
-    fprintf(stderr, "File Loc from '%s': %d: %d\n",
-            getSourceName(), getInstantiationLineNumber(),
-            getInstantiationColumnNumber());
-  } else {
-    fprintf(stderr, "Macro Loc (\n  Spelling: ");
-    getSpellingLoc().dump();
-    fprintf(stderr, "  Instantiation: ");
-    getInstantiationLoc().dump();
-    fprintf(stderr, ")\n");
-  }
-}
diff --git a/lib/Basic/SourceManager.cpp b/lib/Basic/SourceManager.cpp
index 9b509a5..88292cd 100644
--- a/lib/Basic/SourceManager.cpp
+++ b/lib/Basic/SourceManager.cpp
@@ -552,18 +552,31 @@
   return LineNo;
 }
 
-/// getSourceName - This method returns the name of the file or buffer that
-/// the SourceLocation specifies.  This can be modified with #line directives,
-/// etc.
-const char *SourceManager::getSourceName(SourceLocation Loc) const {
-  if (Loc.isInvalid()) return "";
+/// getPresumedLoc - This method returns the "presumed" location of a
+/// SourceLocation specifies.  A "presumed location" can be modified by #line
+/// or GNU line marker directives.  This provides a view on the data that a
+/// user should see in diagnostics, for example.
+///
+/// Note that a presumed location is always given as the instantiation point
+/// of an instantiation location, not at the spelling location.
+PresumedLoc SourceManager::getPresumedLoc(SourceLocation Loc) const {
+  if (Loc.isInvalid()) return PresumedLoc();
   
-  const SrcMgr::ContentCache *C =
-  getSLocEntry(getFileID(getSpellingLoc(Loc))).getFile().getContentCache();
+  // Presumed locations are always for instantiation points.
+  Loc = getInstantiationLoc(Loc);
   
+  // FIXME: Could just decompose Loc once!
+  
+  const SrcMgr::FileInfo &FI = getSLocEntry(getFileID(Loc)).getFile();
+  const SrcMgr::ContentCache *C = FI.getContentCache();
+
   // To get the source name, first consult the FileEntry (if one exists) before
   // the MemBuffer as this will avoid unnecessarily paging in the MemBuffer.
-  return C->Entry ? C->Entry->getName() : C->getBuffer()->getBufferIdentifier();
+  const char *Filename = 
+    C->Entry ? C->Entry->getName() : C->getBuffer()->getBufferIdentifier();
+  
+  return PresumedLoc(Filename, getLineNumber(Loc), getColumnNumber(Loc),
+                     FI.getIncludeLoc());
 }
 
 //===----------------------------------------------------------------------===//
diff --git a/lib/Driver/TextDiagnosticPrinter.cpp b/lib/Driver/TextDiagnosticPrinter.cpp
index 71a5e40..b19d61c 100644
--- a/lib/Driver/TextDiagnosticPrinter.cpp
+++ b/lib/Driver/TextDiagnosticPrinter.cpp
@@ -15,28 +15,26 @@
 #include "clang/Basic/SourceManager.h"
 #include "clang/Lex/Lexer.h"
 #include "llvm/Support/raw_ostream.h"
-#include "llvm/Support/MemoryBuffer.h"
 #include "llvm/ADT/SmallString.h"
 using namespace clang;
 
 void TextDiagnosticPrinter::
-PrintIncludeStack(FullSourceLoc Pos) {
-  if (Pos.isInvalid()) return;
+PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) {
+  if (Loc.isInvalid()) return;
 
-  Pos = Pos.getInstantiationLoc();
+  PresumedLoc PLoc = SM.getPresumedLoc(Loc);
 
   // Print out the other include frames first.
-  PrintIncludeStack(Pos.getIncludeLoc());
-  unsigned LineNo = Pos.getLineNumber();
+  PrintIncludeStack(PLoc.getIncludeLoc(), SM);
   
-  OS << "In file included from " << Pos.getSourceName()
-     << ':' << LineNo << ":\n";
+  OS << "In file included from " << PLoc.getFilename()
+     << ':' << PLoc.getLine() << ":\n";
 }
 
 /// HighlightRange - Given a SourceRange and a line number, highlight (with ~'s)
 /// any characters in LineNo that intersect the SourceRange.
 void TextDiagnosticPrinter::HighlightRange(const SourceRange &R,
-                                           const SourceManager &SourceMgr,
+                                           const SourceManager &SM,
                                            unsigned LineNo, FileID FID,
                                            std::string &CaretLine,
                                            const std::string &SourceLine) {
@@ -44,23 +42,21 @@
          "Expect a correspondence between source and caret line!");
   if (!R.isValid()) return;
 
-  SourceLocation InstantiationStart =
-    SourceMgr.getInstantiationLoc(R.getBegin());
-  unsigned StartLineNo = SourceMgr.getLineNumber(InstantiationStart);
-  if (StartLineNo > LineNo ||
-      SourceMgr.getFileID(InstantiationStart) != FID)
+  SourceLocation Begin = SM.getInstantiationLoc(R.getBegin());
+  SourceLocation End = SM.getInstantiationLoc(R.getEnd());
+  
+  unsigned StartLineNo = SM.getLineNumber(Begin);
+  if (StartLineNo > LineNo || SM.getFileID(Begin) != FID)
     return;  // No intersection.
   
-  SourceLocation InstantiationEnd = SourceMgr.getInstantiationLoc(R.getEnd());
-  unsigned EndLineNo = SourceMgr.getLineNumber(InstantiationEnd);
-  if (EndLineNo < LineNo ||
-      SourceMgr.getFileID(InstantiationEnd) != FID)
+  unsigned EndLineNo = SM.getLineNumber(End);
+  if (EndLineNo < LineNo || SM.getFileID(End) != FID)
     return;  // No intersection.
   
   // Compute the column number of the start.
   unsigned StartColNo = 0;
   if (StartLineNo == LineNo) {
-    StartColNo = SourceMgr.getInstantiationColumnNumber(R.getBegin());
+    StartColNo = SM.getColumnNumber(Begin);
     if (StartColNo) --StartColNo;  // Zero base the col #.
   }
 
@@ -72,12 +68,12 @@
   // Compute the column number of the end.
   unsigned EndColNo = CaretLine.size();
   if (EndLineNo == LineNo) {
-    EndColNo = SourceMgr.getInstantiationColumnNumber(R.getEnd());
+    EndColNo = SM.getColumnNumber(End);
     if (EndColNo) {
       --EndColNo;  // Zero base the col #.
       
       // Add in the length of the token, so that we cover multi-char tokens.
-      EndColNo += Lexer::MeasureTokenLength(R.getEnd(), SourceMgr);
+      EndColNo += Lexer::MeasureTokenLength(End, SM);
     } else {
       EndColNo = CaretLine.size();
     }
@@ -99,39 +95,25 @@
 
 void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, 
                                              const DiagnosticInfo &Info) {
-  unsigned LineNo = 0, ColNo = 0;
-  FileID FID;
-  const char *LineStart = 0, *LineEnd = 0;
-  const FullSourceLoc &Pos = Info.getLocation();
+  const SourceManager &SM = Info.getLocation().getManager();
+  unsigned ColNo = 0;
   
-  if (Pos.isValid()) {
-    FullSourceLoc LPos = Pos.getInstantiationLoc();
-    FID = LPos.getFileID();
-    LineNo = LPos.getLineNumber();
+  // If the location is specified, print out a file/line/col and include trace
+  // if enabled.
+  if (Info.getLocation().isValid()) {
+    PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation());
+    unsigned LineNo = PLoc.getLine();
     
     // First, if this diagnostic is not in the main file, print out the
     // "included from" lines.
-    if (LastWarningLoc != LPos.getIncludeLoc()) {
-      LastWarningLoc = LPos.getIncludeLoc();
-      PrintIncludeStack(LastWarningLoc);
+    if (LastWarningLoc != PLoc.getIncludeLoc()) {
+      LastWarningLoc = PLoc.getIncludeLoc();
+      PrintIncludeStack(LastWarningLoc, SM);
     }
   
-    // Compute the column number.  Rewind from the current position to the start
-    // of the line.
-    ColNo = LPos.getColumnNumber();
-    const char *TokInstantiationPtr = LPos.getCharacterData();
-    LineStart = TokInstantiationPtr-ColNo+1;  // Column # is 1-based
-
-    // Compute the line end.  Scan forward from the error position to the end of
-    // the line.
-    const llvm::MemoryBuffer *Buffer = LPos.getBuffer();
-    const char *BufEnd = Buffer->getBufferEnd();
-    LineEnd = TokInstantiationPtr;
-    while (LineEnd != BufEnd && 
-           *LineEnd != '\n' && *LineEnd != '\r')
-      ++LineEnd;
-  
-    OS << Buffer->getBufferIdentifier() << ':' << LineNo << ':';
+    // Compute the column number.
+    ColNo = PLoc.getColumn();
+    OS << PLoc.getFilename() << ':' << LineNo << ':';
     if (ColNo && ShowColumn) 
       OS << ColNo << ':';
     OS << ' ';
@@ -149,21 +131,49 @@
   OS.write(OutStr.begin(), OutStr.size());
   OS << '\n';
   
-  if (CaretDiagnostics && Pos.isValid() &&
-      ((LastLoc != Pos) || Info.getNumRanges())) {
+  // If caret diagnostics are enabled and we have location, we want to emit the
+  // caret.  However, we only do this if the location moved from the last
+  // diagnostic, or if the diagnostic has ranges.  We don't want to emit the
+  // same caret multiple times if one loc has multiple diagnostics.
+  if (CaretDiagnostics && Info.getLocation().isValid() &&
+      ((LastLoc != Info.getLocation()) || Info.getNumRanges())) {
     // Cache the LastLoc, it allows us to omit duplicate source/caret spewage.
-    LastLoc = Pos;
+    LastLoc = Info.getLocation();
+
+    // Inspect the actual instantiation point of the diagnostic, we don't care
+    // about presumed locations anymore.
+    SourceLocation ILoc = SM.getInstantiationLoc(Info.getLocation());
     
-    // Get the line of the source file.
+    // Get the file and line that we want to highlight.  We only draw ranges
+    // that intersect this.
+    FileID ILocFID = SM.getFileID(ILoc);
+    unsigned LineNo = SM.getLineNumber(ILoc);
+    
+    // Get the line of the source file.  Scan from the location backward and
+    // forward to find the start/end of the line.
+    
+    // Rewind from the current position to the start of the line.
+    const char *TokInstantiationPtr = SM.getCharacterData(ILoc);
+    const char *LineStart = TokInstantiationPtr-ColNo+1; // Column # is 1-based.
+    
+    // Compute the line end.  Scan forward from the error position to the end of
+    // the line.
+    const char *BufEnd = SM.getBufferData(ILocFID).second;
+    const char *LineEnd = TokInstantiationPtr;
+    while (LineEnd != BufEnd && 
+           *LineEnd != '\n' && *LineEnd != '\r')
+      ++LineEnd;
+    
+    // Copy the line of code into an std::string for ease of manipulation.
     std::string SourceLine(LineStart, LineEnd);
     
     // Create a line for the caret that is filled with spaces that is the same
     // length as the line of source code.
     std::string CaretLine(LineEnd-LineStart, ' ');
-    
+
     // Highlight all of the characters covered by Ranges with ~ characters.
     for (unsigned i = 0; i != Info.getNumRanges(); ++i)
-      HighlightRange(Info.getRange(i), Pos.getManager(), LineNo, FID,
+      HighlightRange(Info.getRange(i), SM, LineNo, ILocFID,
                      CaretLine, SourceLine);
     
     // Next, insert the caret itself.
diff --git a/lib/Lex/PPMacroExpansion.cpp b/lib/Lex/PPMacroExpansion.cpp
index 8eada60..a517b1d 100644
--- a/lib/Lex/PPMacroExpansion.cpp
+++ b/lib/Lex/PPMacroExpansion.cpp
@@ -454,28 +454,37 @@
   Tok.clearFlag(Token::NeedsCleaning);
   
   if (II == Ident__LINE__) {
+    // C99 6.10.8: "__LINE__: The presumed line number (within the current
+    // source file) of the current source line (an integer constant)".  This can
+    // be affected by #line.
+    PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation());
+    
     // __LINE__ expands to a simple numeric value.  Add a space after it so that
     // it will tokenize as a number (and not run into stuff after it in the temp
     // buffer).
-    sprintf(TmpBuffer, "%u ",
-            SourceMgr.getInstantiationLineNumber(Tok.getLocation()));
+    sprintf(TmpBuffer, "%u ", PLoc.getLine());
     unsigned Length = strlen(TmpBuffer)-1;
     Tok.setKind(tok::numeric_constant);
     CreateString(TmpBuffer, Length+1, Tok, Tok.getLocation());
     Tok.setLength(Length);  // Trim off space.
   } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) {
-    SourceLocation Loc = Tok.getLocation();
+    // C99 6.10.8: "__FILE__: The presumed name of the current source file (a
+    // character string literal)". This can be affected by #line.
+    PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation());
+
+    // __BASE_FILE__ is a GNU extension that returns the top of the presumed
+    // #include stack instead of the current file.
     if (II == Ident__BASE_FILE__) {
       Diag(Tok, diag::ext_pp_base_file);
-      SourceLocation NextLoc = SourceMgr.getIncludeLoc(Loc);
+      SourceLocation NextLoc = PLoc.getIncludeLoc();
       while (NextLoc.isValid()) {
-        Loc = NextLoc;
-        NextLoc = SourceMgr.getIncludeLoc(Loc);
+        PLoc = SourceMgr.getPresumedLoc(NextLoc);
+        NextLoc = PLoc.getIncludeLoc();
       }
     }
     
     // Escape this filename.  Turn '\' -> '\\' '"' -> '\"'
-    std::string FN =SourceMgr.getSourceName(SourceMgr.getInstantiationLoc(Loc));
+    std::string FN = PLoc.getFilename();
     FN = '"' + Lexer::Stringify(FN) + '"';
     Tok.setKind(tok::string_literal);
     CreateString(&FN[0], FN.size(), Tok, Tok.getLocation());
@@ -496,11 +505,14 @@
   } else if (II == Ident__INCLUDE_LEVEL__) {
     Diag(Tok, diag::ext_pp_include_level);
 
-    // Compute the include depth of this token.
+    // Compute the presumed include depth of this token.  This can be affected
+    // by GNU line markers.
     unsigned Depth = 0;
-    SourceLocation Loc = SourceMgr.getIncludeLoc(Tok.getLocation());
-    for (; Loc.isValid(); ++Depth)
-      Loc = SourceMgr.getIncludeLoc(Loc);
+    
+    PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation());
+    PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc());
+    for (; PLoc.isValid(); ++Depth)
+      PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc());
     
     // __INCLUDE_LEVEL__ expands to a simple numeric value.  Add a space after
     // it so that it will tokenize as a number (and not run into stuff after it
diff --git a/lib/Lex/Preprocessor.cpp b/lib/Lex/Preprocessor.cpp
index e6bf177..48fdd68 100644
--- a/lib/Lex/Preprocessor.cpp
+++ b/lib/Lex/Preprocessor.cpp
@@ -142,17 +142,7 @@
 }
 
 void Preprocessor::DumpLocation(SourceLocation Loc) const {
-  SourceLocation LogLoc = SourceMgr.getInstantiationLoc(Loc);
-  llvm::cerr << SourceMgr.getSourceName(LogLoc) << ':'
-             << SourceMgr.getLineNumber(LogLoc) << ':'
-             << SourceMgr.getColumnNumber(LogLoc);
-  
-  SourceLocation SpellingLoc = SourceMgr.getSpellingLoc(Loc);
-  if (SpellingLoc != LogLoc) {
-    llvm::cerr << " <SpellingLoc=";
-    DumpLocation(SpellingLoc);
-    llvm::cerr << ">";
-  }
+  Loc.dump(SourceMgr);
 }
 
 void Preprocessor::DumpMacro(const MacroInfo &MI) const {