From b9c3f966b103f7cfe8e5e60007c4c8b38f7298eb Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Tue, 27 Jan 2009 07:57:44 +0000 Subject: [PATCH] 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 --- Driver/AnalysisConsumer.cpp | 18 ++- Driver/DependencyFile.cpp | 11 +- Driver/PrintPreprocessedOutput.cpp | 7 +- include/clang/Basic/SourceLocation.h | 57 +++++++-- include/clang/Basic/SourceManager.h | 20 ++-- include/clang/Driver/TextDiagnosticPrinter.h | 4 +- lib/AST/StmtDumper.cpp | 27 +++-- lib/Analysis/LiveVariables.cpp | 10 +- lib/Basic/SourceLocation.cpp | 52 ++++---- lib/Basic/SourceManager.cpp | 29 +++-- lib/Driver/TextDiagnosticPrinter.cpp | 118 ++++++++++--------- lib/Lex/PPMacroExpansion.cpp | 34 ++++-- lib/Lex/Preprocessor.cpp | 12 +- test/Preprocessor/dumptokens_phyloc.c | 2 +- 14 files changed, 230 insertions(+), 171 deletions(-) diff --git a/Driver/AnalysisConsumer.cpp b/Driver/AnalysisConsumer.cpp index 4dab9c7b4b..171ffbf2df 100644 --- a/Driver/AnalysisConsumer.cpp +++ b/Driver/AnalysisConsumer.cpp @@ -257,18 +257,14 @@ case PD_##NAME: C.PD.reset(CREATEFN(C.HTMLDir, C.PP, C.PPF)); break; DisplayedFunction = true; - if (FunctionDecl *FD = dyn_cast(getCodeDecl())) { + // FIXME: Is getCodeDecl() always a named decl? + if (isa(getCodeDecl()) || + isa(getCodeDecl())) { + NamedDecl *ND = cast(getCodeDecl()); + SourceManager &SM = getContext().getSourceManager(); llvm::cerr << "ANALYZE: " - << getContext().getSourceManager().getSourceName(FD->getLocation()) - << ' ' - << FD->getIdentifier()->getName() - << '\n'; - } - else if (ObjCMethodDecl *MD = dyn_cast(getCodeDecl())) { - llvm::cerr << "ANALYZE (ObjC Method): " - << getContext().getSourceManager().getSourceName(MD->getLocation()) - << " '" - << MD->getSelector().getAsString() << "'\n"; + << SM.getPresumedLoc(ND->getLocation()).getFilename() + << ' ' << ND->getNameAsString() << '\n'; } } diff --git a/Driver/DependencyFile.cpp b/Driver/DependencyFile.cpp index 282164fdd6..0d4ee91f01 100644 --- a/Driver/DependencyFile.cpp +++ b/Driver/DependencyFile.cpp @@ -13,6 +13,7 @@ #include "clang.h" #include "clang/Basic/SourceManager.h" +#include "clang/Basic/FileManager.h" #include "clang/Lex/Preprocessor.h" #include "clang/Lex/PPCallbacks.h" #include "clang/Lex/DirectoryLookup.h" @@ -167,8 +168,14 @@ void DependencyFileCallback::FileChanged(SourceLocation Loc, SrcMgr::CharacteristicKind FileType) { if (Reason != PPCallbacks::EnterFile) return; - - const char *Filename = PP->getSourceManager().getSourceName(Loc); + + // Depedency generation really does want to go all the way to the file entry + // for a source location to find out what is depended on. We do not want + // #line markers to affect dependency generation! + SourceManager &SM = PP->getSourceManager(); + + FileID FID = SM.getFileID(SM.getInstantiationLoc(Loc)); + const char *Filename = SM.getFileEntryForID(FID)->getName(); if (!FileMatchesDepCriteria(Filename, FileType)) return; diff --git a/Driver/PrintPreprocessedOutput.cpp b/Driver/PrintPreprocessedOutput.cpp index 32b8a8b279..5c4a140fa9 100644 --- a/Driver/PrintPreprocessedOutput.cpp +++ b/Driver/PrintPreprocessedOutput.cpp @@ -150,7 +150,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, // #include directive was at. SourceManager &SourceMgr = PP.getSourceManager(); if (Reason == PPCallbacks::EnterFile) { - MoveToLine(SourceMgr.getIncludeLoc(Loc)); + MoveToLine(SourceMgr.getPresumedLoc(Loc).getIncludeLoc()); } else if (Reason == PPCallbacks::SystemHeaderPragma) { MoveToLine(Loc); @@ -165,7 +165,7 @@ void PrintPPOutputPPCallbacks::FileChanged(SourceLocation Loc, if (DisableLineMarkers) return; CurFilename.clear(); - CurFilename += SourceMgr.getSourceName(Loc); + CurFilename += SourceMgr.getPresumedLoc(Loc).getFilename(); Lexer::Stringify(CurFilename); FileType = NewFileType; @@ -540,7 +540,8 @@ void clang::DoPrintPreprocessedInput(Preprocessor &PP, const SourceManager &SourceMgr = PP.getSourceManager(); do PP.Lex(Tok); while (Tok.isNot(tok::eof) && Tok.getLocation().isFileID() && - !strcmp(SourceMgr.getSourceName(Tok.getLocation()), "")); + !strcmp(SourceMgr.getPresumedLoc(Tok.getLocation()).getFilename(), + "")); while (1) { diff --git a/include/clang/Basic/SourceLocation.h b/include/clang/Basic/SourceLocation.h index 6da9a87ee3..31fbc0218b 100644 --- a/include/clang/Basic/SourceLocation.h +++ b/include/clang/Basic/SourceLocation.h @@ -133,6 +133,8 @@ public: /// ReadVal - Read a SourceLocation object from Bitcode. static SourceLocation ReadVal(llvm::Deserializer& D); + + void dump(const SourceManager &SM) const; }; inline bool operator==(const SourceLocation &LHS, const SourceLocation &RHS) { @@ -182,13 +184,13 @@ public: explicit FullSourceLoc(SourceLocation Loc, SourceManager &SM) : SourceLocation(Loc), SrcMgr(&SM) {} - SourceManager& getManager() { - assert (SrcMgr && "SourceManager is NULL."); + SourceManager &getManager() { + assert(SrcMgr && "SourceManager is NULL."); return *SrcMgr; } - const SourceManager& getManager() const { - assert (SrcMgr && "SourceManager is NULL."); + const SourceManager &getManager() const { + assert(SrcMgr && "SourceManager is NULL."); return *SrcMgr; } @@ -196,7 +198,6 @@ public: FullSourceLoc getInstantiationLoc() const; FullSourceLoc getSpellingLoc() const; - FullSourceLoc getIncludeLoc() const; unsigned getLineNumber() const; unsigned getColumnNumber() const; @@ -211,13 +212,11 @@ public: const llvm::MemoryBuffer* getBuffer() const; - const char* getSourceName() const; - bool isInSystemHeader() const; /// Prints information about this FullSourceLoc to stderr. Useful for /// debugging. - void dump() const; + void dump() const { SourceLocation::dump(*SrcMgr); } friend inline bool operator==(const FullSourceLoc &LHS, const FullSourceLoc &RHS) { @@ -231,7 +230,47 @@ public: } }; - + +/// PresumedLoc - This class represents an unpacked "presumed" location which +/// can be presented to the user. A 'presumed' location can be modified by +/// #line and GNU line marker directives and is always the instantiation point +/// of a normal location. +/// +/// You can get a PresumedLoc from a SourceLocation with SourceManager. +class PresumedLoc { + const char *Filename; + unsigned Line, Col; + SourceLocation IncludeLoc; +public: + PresumedLoc() : Filename(0) {} + PresumedLoc(const char *FN, unsigned Ln, unsigned Co, SourceLocation IL) + : Filename(FN), Line(Ln), Col(Co), IncludeLoc(IL) { + } + + /// isInvalid - Return true if this object is invalid or uninitialized. This + /// occurs when created with invalid source locations or when walking off + /// the top of a #include stack. + bool isInvalid() const { return Filename == 0; } + bool isValid() const { return Filename != 0; } + + /// getFilename - Return the presumed filename of this location. This can be + /// affected by #line etc. + const char *getFilename() const { return Filename; } + + /// getLine - Return the presumed line number of this location. This can be + /// affected by #line etc. + unsigned getLine() const { return Line; } + + /// getColumn - Return the presumed column number of this location. This can + /// not be affected by #line, but is packaged here for convenience. + unsigned getColumn() const { return Col; } + + /// getIncludeLoc - Return the presumed include location of this location. + /// This can be affected by GNU linemarker directives. + SourceLocation getIncludeLoc() const { return IncludeLoc; } +}; + + } // end namespace clang namespace llvm { diff --git a/include/clang/Basic/SourceManager.h b/include/clang/Basic/SourceManager.h index dab3badea2..a63ef79037 100644 --- a/include/clang/Basic/SourceManager.h +++ b/include/clang/Basic/SourceManager.h @@ -404,14 +404,6 @@ public: return SourceLocation::getFileLoc(FileOffset); } - /// getIncludeLoc - Return the location of the #include for the specified - /// SourceLocation. If this is a macro expansion, this transparently figures - /// out which file includes the file being expanded into. - SourceLocation getIncludeLoc(SourceLocation ID) const { - return getSLocEntry(getFileID(getInstantiationLoc(ID))) - .getFile().getIncludeLoc(); - } - /// Given a SourceLocation object, return the instantiation location /// referenced by the ID. SourceLocation getInstantiationLoc(SourceLocation Loc) const { @@ -518,10 +510,14 @@ public: return getSLocEntry(FID).getFile().getFileCharacteristic(); } - /// 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 *getSourceName(SourceLocation Loc) const; + /// 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 getPresumedLoc(SourceLocation Loc) const; diff --git a/include/clang/Driver/TextDiagnosticPrinter.h b/include/clang/Driver/TextDiagnosticPrinter.h index 550c337b50..b49094dcb1 100644 --- a/include/clang/Driver/TextDiagnosticPrinter.h +++ b/include/clang/Driver/TextDiagnosticPrinter.h @@ -26,7 +26,7 @@ namespace clang { class SourceManager; class TextDiagnosticPrinter : public DiagnosticClient { - FullSourceLoc LastWarningLoc; + SourceLocation LastWarningLoc; FullSourceLoc LastLoc; llvm::raw_ostream &OS; bool ShowColumn; @@ -36,7 +36,7 @@ public: bool caretDiagnistics = true) : OS(os), ShowColumn(showColumn), CaretDiagnostics(caretDiagnistics) {} - void PrintIncludeStack(FullSourceLoc Pos); + void PrintIncludeStack(SourceLocation Loc, const SourceManager &SM); void HighlightRange(const SourceRange &R, const SourceManager& SrcMgr, diff --git a/lib/AST/StmtDumper.cpp b/lib/AST/StmtDumper.cpp index 0a7de350d0..83313ed9be 100644 --- a/lib/AST/StmtDumper.cpp +++ b/lib/AST/StmtDumper.cpp @@ -153,21 +153,26 @@ namespace { void StmtDumper::DumpLocation(SourceLocation Loc) { SourceLocation SpellingLoc = SM->getSpellingLoc(Loc); + + if (SpellingLoc.isInvalid()) { + fprintf(stderr, ""); + 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 ac0aa9ba8c..4c86d44e4d 100644 --- a/lib/Analysis/LiveVariables.cpp +++ b/lib/Analysis/LiveVariables.cpp @@ -358,13 +358,9 @@ void LiveVariables::dumpLiveness(const ValTy& V, SourceManager& SM) const { 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 f0c8274de9..5d484721bd 100644 --- a/lib/Basic/SourceLocation.cpp +++ b/lib/Basic/SourceLocation.cpp @@ -26,6 +26,29 @@ SourceLocation SourceLocation::ReadVal(llvm::Deserializer& D) { return SourceLocation::getFromRawEncoding(D.ReadInt()); } +void SourceLocation::dump(const SourceManager &SM) const { + if (!isValid()) { + fprintf(stderr, ""); + 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, " "); +} + + void SourceRange::Emit(llvm::Serializer& S) const { B.Emit(S); E.Emit(S); @@ -53,11 +76,6 @@ FullSourceLoc FullSourceLoc::getSpellingLoc() const { 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 @@ unsigned FullSourceLoc::getSpellingColumnNumber() const { 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 @@ const llvm::MemoryBuffer* FullSourceLoc::getBuffer() const { 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 9b509a5684..88292cd42b 100644 --- a/lib/Basic/SourceManager.cpp +++ b/lib/Basic/SourceManager.cpp @@ -552,18 +552,31 @@ unsigned SourceManager::getLineNumber(SourceLocation Loc) const { 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(); + + // Presumed locations are always for instantiation points. + Loc = getInstantiationLoc(Loc); - const SrcMgr::ContentCache *C = - getSLocEntry(getFileID(getSpellingLoc(Loc))).getFile().getContentCache(); + // 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 71a5e40107..b19d61c160 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 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, "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 @@ void TextDiagnosticPrinter::HighlightRange(const SourceRange &R, // 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::HighlightRange(const SourceRange &R, 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 @@ void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, 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 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. + // 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 8eada6003d..a517b1d4f5 100644 --- a/lib/Lex/PPMacroExpansion.cpp +++ b/lib/Lex/PPMacroExpansion.cpp @@ -454,28 +454,37 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { 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 @@ void Preprocessor::ExpandBuiltinMacro(Token &Tok) { } 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 e6bf1777a8..48fdd68ab9 100644 --- a/lib/Lex/Preprocessor.cpp +++ b/lib/Lex/Preprocessor.cpp @@ -142,17 +142,7 @@ void Preprocessor::DumpToken(const Token &Tok, bool DumpFlags) const { } 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 << " "; - } + Loc.dump(SourceMgr); } void Preprocessor::DumpMacro(const MacroInfo &MI) const { diff --git a/test/Preprocessor/dumptokens_phyloc.c b/test/Preprocessor/dumptokens_phyloc.c index e48a9d44ab..ae7ccc7d21 100644 --- a/test/Preprocessor/dumptokens_phyloc.c +++ b/test/Preprocessor/dumptokens_phyloc.c @@ -1,4 +1,4 @@ -// RUN: clang -dump-tokens %s 2>&1 | grep "SpellingLoc=.*dumptokens_phyloc.c:3:20" +// RUN: clang -dump-tokens %s 2>&1 | grep "Spelling=.*dumptokens_phyloc.c:3:20" #define TESTPHYLOC 10 -- 2.40.0