diff options
author | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-04-08 18:45:10 +0000 |
commit | c72c57c9e9b69944e3e009cd5e209634839581d3 (patch) | |
tree | 4fc2f184c499d106f29a386c452b49e5197bf63d /lib/Frontend/DiagnosticRenderer.cpp | |
parent | 5b20025c30d23d521e12c1f33ec8fa6b821952cd (diff) | |
download | FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.zip FreeBSD-src-c72c57c9e9b69944e3e009cd5e209634839581d3.tar.gz |
Vendor import of clang trunk r178860:
http://llvm.org/svn/llvm-project/cfe/trunk@178860
Diffstat (limited to 'lib/Frontend/DiagnosticRenderer.cpp')
-rw-r--r-- | lib/Frontend/DiagnosticRenderer.cpp | 326 |
1 files changed, 231 insertions, 95 deletions
diff --git a/lib/Frontend/DiagnosticRenderer.cpp b/lib/Frontend/DiagnosticRenderer.cpp index 359b82b..3b4f55c 100644 --- a/lib/Frontend/DiagnosticRenderer.cpp +++ b/lib/Frontend/DiagnosticRenderer.cpp @@ -11,15 +11,15 @@ #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" -#include "clang/Lex/Lexer.h" -#include "clang/Edit/EditedSource.h" #include "clang/Edit/Commit.h" +#include "clang/Edit/EditedSource.h" #include "clang/Edit/EditsReceiver.h" -#include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/raw_ostream.h" -#include "llvm/Support/ErrorHandling.h" +#include "clang/Lex/Lexer.h" #include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallString.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/raw_ostream.h" #include <algorithm> using namespace clang; @@ -47,6 +47,11 @@ static StringRef getImmediateMacroName(SourceLocation Loc, while (SM.isMacroArgExpansion(Loc)) Loc = SM.getImmediateExpansionRange(Loc).first; + // If the macro's spelling has no FileID, then it's actually a token paste + // or stringization (or similar) and not a macro at all. + if (!SM.getFileEntryForID(SM.getFileID(SM.getSpellingLoc(Loc)))) + return StringRef(); + // 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. @@ -123,28 +128,18 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, const SourceManager *SM, DiagOrStoredDiag D) { assert(SM || Loc.isInvalid()); - + beginDiagnostic(D, Level); - - PresumedLoc PLoc; - if (Loc.isValid()) { - PLoc = SM->getPresumedLocForDisplay(Loc); - - // First, if this diagnostic is not in the main file, print out the - // "included from" lines. - emitIncludeStack(PLoc.getIncludeLoc(), Level, *SM); - } - - // Next, emit the actual diagnostic message. - emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); - - // Only recurse if we have a valid location. - if (Loc.isValid()) { + + if (!Loc.isValid()) + // If we have no source location, just emit the diagnostic message. + emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, SM, D); + else { // Get the ranges into a local array we can hack on. SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), Ranges.end()); - - llvm::SmallVector<FixItHint, 8> MergedFixits; + + SmallVector<FixItHint, 8> MergedFixits; if (!FixItHints.empty()) { mergeFixits(FixItHints, *SM, LangOpts, MergedFixits); FixItHints = MergedFixits; @@ -155,15 +150,34 @@ void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, I != E; ++I) if (I->RemoveRange.isValid()) MutableRanges.push_back(I->RemoveRange); - - unsigned MacroDepth = 0; - emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, *SM, - MacroDepth); + + SourceLocation UnexpandedLoc = Loc; + + // Find the ultimate expansion location for the diagnostic. + Loc = SM->getFileLoc(Loc); + + PresumedLoc PLoc = SM->getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + + // First, if this diagnostic is not in the main file, print out the + // "included from" lines. + emitIncludeStack(Loc, PLoc, Level, *SM); + + // Next, emit the actual diagnostic message and caret. + emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); + emitCaret(Loc, Level, MutableRanges, FixItHints, *SM); + + // If this location is within a macro, walk from UnexpandedLoc up to Loc + // and produce a macro backtrace. + if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) { + unsigned MacroDepth = 0; + emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM, + MacroDepth); + } } - + LastLoc = Loc; LastLevel = Level; - + endDiagnostic(D, Level); } @@ -184,34 +198,55 @@ void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { /// repeated warnings occur within the same file. It also handles the logic /// of customizing the formatting and display of the include stack. /// +/// \param Loc The diagnostic location. +/// \param PLoc The presumed location of the diagnostic location. /// \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, + PresumedLoc PLoc, DiagnosticsEngine::Level Level, const SourceManager &SM) { + SourceLocation IncludeLoc = PLoc.getIncludeLoc(); + // Skip redundant include stacks altogether. - if (LastIncludeLoc == Loc) + if (LastIncludeLoc == IncludeLoc) return; - LastIncludeLoc = Loc; + + LastIncludeLoc = IncludeLoc; if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) return; - - emitIncludeStackRecursively(Loc, SM); + + if (IncludeLoc.isValid()) + emitIncludeStackRecursively(IncludeLoc, SM); + else { + emitModuleBuildStack(SM); + emitImportStack(Loc, SM); + } } /// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM) { - if (Loc.isInvalid()) + if (Loc.isInvalid()) { + emitModuleBuildStack(SM); return; + } - PresumedLoc PLoc = SM.getPresumedLoc(Loc); + PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); if (PLoc.isInvalid()) return; - + + // If this source location was imported from a module, print the module + // import stack rather than the + // FIXME: We want submodule granularity here. + std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc); + if (Imported.first.isValid()) { + // This location was imported by a module. Emit the module import stack. + emitImportStackRecursively(Imported.first, Imported.second, SM); + return; + } + // Emit the other include frames first. emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); @@ -219,6 +254,56 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, emitIncludeLocation(Loc, PLoc, SM); } +/// \brief Emit the module import stack associated with the current location. +void DiagnosticRenderer::emitImportStack(SourceLocation Loc, + const SourceManager &SM) { + if (Loc.isInvalid()) { + emitModuleBuildStack(SM); + return; + } + + std::pair<SourceLocation, StringRef> NextImportLoc + = SM.getModuleImportLoc(Loc); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); +} + +/// \brief Helper to recursivly walk up the import stack and print each layer +/// on the way back down. +void DiagnosticRenderer::emitImportStackRecursively(SourceLocation Loc, + StringRef ModuleName, + const SourceManager &SM) { + if (Loc.isInvalid()) { + return; + } + + PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); + if (PLoc.isInvalid()) + return; + + // Emit the other import frames first. + std::pair<SourceLocation, StringRef> NextImportLoc + = SM.getModuleImportLoc(Loc); + emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM); + + // Emit the inclusion text/note. + emitImportLocation(Loc, PLoc, ModuleName, SM); +} + +/// \brief Emit the module build stack, for cases where a module is (re-)built +/// on demand. +void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) { + ModuleBuildStack Stack = SM.getModuleBuildStack(); + for (unsigned I = 0, N = Stack.size(); I != N; ++I) { + const SourceManager &CurSM = Stack[I].second.getManager(); + SourceLocation CurLoc = Stack[I].second; + emitBuildingModuleLocation(CurLoc, + CurSM.getPresumedLoc(CurLoc, + DiagOpts->ShowPresumedLoc), + Stack[I].first, + CurSM); + } +} + // Helper function to fix up source ranges. It takes in an array of ranges, // and outputs an array of ranges where we want to draw the range highlighting // around the location specified by CaretLoc. @@ -231,31 +316,58 @@ void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, // iff the FileID is the same. static void mapDiagnosticRanges( SourceLocation CaretLoc, - const SmallVectorImpl<CharSourceRange>& Ranges, - SmallVectorImpl<CharSourceRange>& SpellingRanges, + ArrayRef<CharSourceRange> Ranges, + SmallVectorImpl<CharSourceRange> &SpellingRanges, const SourceManager *SM) { FileID CaretLocFileID = SM->getFileID(CaretLoc); - for (SmallVectorImpl<CharSourceRange>::const_iterator I = Ranges.begin(), + for (ArrayRef<CharSourceRange>::const_iterator I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { SourceLocation Begin = I->getBegin(), End = I->getEnd(); bool IsTokenRange = I->isTokenRange(); - // Search the macro caller chain for the beginning of the range. - while (Begin.isMacroID() && SM->getFileID(Begin) != CaretLocFileID) - Begin = SM->getImmediateMacroCallerLoc(Begin); + FileID BeginFileID = SM->getFileID(Begin); + FileID EndFileID = SM->getFileID(End); - // Search the macro caller chain for the beginning of the range. - while (End.isMacroID() && SM->getFileID(End) != CaretLocFileID) { - // The computation of the next End is an inlined version of - // getImmediateMacroCallerLoc, except it chooses the end of an - // expansion range. - if (SM->isMacroArgExpansion(End)) { + // Find the common parent for the beginning and end of the range. + + // First, crawl the expansion chain for the beginning of the range. + llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap; + while (Begin.isMacroID() && BeginFileID != EndFileID) { + BeginLocsMap[BeginFileID] = Begin; + Begin = SM->getImmediateExpansionRange(Begin).first; + BeginFileID = SM->getFileID(Begin); + } + + // Then, crawl the expansion chain for the end of the range. + if (BeginFileID != EndFileID) { + while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) { + End = SM->getImmediateExpansionRange(End).second; + EndFileID = SM->getFileID(End); + } + if (End.isMacroID()) { + Begin = BeginLocsMap[EndFileID]; + BeginFileID = EndFileID; + } + } + + while (Begin.isMacroID() && BeginFileID != CaretLocFileID) { + if (SM->isMacroArgExpansion(Begin)) { + Begin = SM->getImmediateSpellingLoc(Begin); End = SM->getImmediateSpellingLoc(End); } else { + Begin = SM->getImmediateExpansionRange(Begin).first; End = SM->getImmediateExpansionRange(End).second; } + BeginFileID = SM->getFileID(Begin); + if (BeginFileID != SM->getFileID(End)) { + // FIXME: Ugly hack to stop a crash; this code is making bad + // assumptions and it's too complicated for me to reason + // about. + Begin = End = SourceLocation(); + break; + } } // Return the spelling location of the beginning and end of the range. @@ -266,6 +378,16 @@ static void mapDiagnosticRanges( } } +void DiagnosticRenderer::emitCaret(SourceLocation Loc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM) { + SmallVector<CharSourceRange, 4> SpellingRanges; + mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); + emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); +} + /// \brief Recursively emit notes for each macro expansion and caret /// diagnostics where appropriate. /// @@ -277,48 +399,24 @@ static void mapDiagnosticRanges( /// \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, - const SourceManager &SM, - unsigned &MacroDepth, - unsigned OnMacroInst) -{ +void DiagnosticRenderer::emitMacroExpansions(SourceLocation Loc, + DiagnosticsEngine::Level Level, + ArrayRef<CharSourceRange> Ranges, + ArrayRef<FixItHint> Hints, + const SourceManager &SM, + 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()) { - // Map the ranges. - SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); - - assert(MacroDepth == 0 && "We shouldn't hit a leaf node twice!"); - MacroDepth = OnMacroInst; - emitCodeContext(Loc, Level, SpellingRanges, Hints, SM); - 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 = SM.skipToMacroArgExpansion(Loc); - + + // Walk up to the caller of this macro, and produce a backtrace down to there. SourceLocation OneLevelUp = SM.getImmediateMacroCallerLoc(Loc); + if (OneLevelUp.isMacroID()) + emitMacroExpansions(OneLevelUp, Level, Ranges, Hints, SM, + MacroDepth, OnMacroInst + 1); + else + MacroDepth = OnMacroInst + 1; - emitMacroExpansionsAndCarets(OneLevelUp, Level, Ranges, Hints, SM, MacroDepth, - OnMacroInst + 1); - - // Save the original location so we can find the spelling of the macro call. - SourceLocation MacroLoc = Loc; - - // Map the location. - Loc = SM.getImmediateMacroCalleeLoc(Loc); - unsigned MacroSkipStart = 0, MacroSkipEnd = 0; if (MacroDepth > DiagOpts->MacroBacktraceLimit && DiagOpts->MacroBacktraceLimit != 0) { @@ -326,11 +424,11 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( DiagOpts->MacroBacktraceLimit % 2; MacroSkipEnd = MacroDepth - DiagOpts->MacroBacktraceLimit / 2; } - + // Whether to suppress printing this macro expansion. bool Suppressed = (OnMacroInst >= MacroSkipStart && OnMacroInst < MacroSkipEnd); - + if (Suppressed) { // Tell the user that we've skipped contexts. if (OnMacroInst == MacroSkipStart) { @@ -344,15 +442,27 @@ void DiagnosticRenderer::emitMacroExpansionsAndCarets( return; } - // Map the ranges. + // Find the spelling location for the macro definition. We must use the + // spelling location here to avoid emitting a macro bactrace for the note. + SourceLocation SpellingLoc = Loc; + // If this is the expansion of a macro argument, point the caret at the + // use of the argument in the definition of the macro, not the expansion. + if (SM.isMacroArgExpansion(Loc)) + SpellingLoc = SM.getImmediateExpansionRange(Loc).first; + SpellingLoc = SM.getSpellingLoc(SpellingLoc); + + // Map the ranges into the FileID of the diagnostic location. SmallVector<CharSourceRange, 4> SpellingRanges; - mapDiagnosticRanges(MacroLoc, Ranges, SpellingRanges, &SM); + mapDiagnosticRanges(Loc, Ranges, SpellingRanges, &SM); SmallString<100> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); - Message << "expanded from macro '" - << getImmediateMacroName(MacroLoc, SM, LangOpts) << "'"; - emitDiagnostic(SM.getSpellingLoc(Loc), DiagnosticsEngine::Note, + StringRef MacroName = getImmediateMacroName(Loc, SM, LangOpts); + if (MacroName.empty()) + Message << "expanded from here"; + else + Message << "expanded from macro '" << MacroName << "'"; + emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), SpellingRanges, ArrayRef<FixItHint>(), &SM); } @@ -370,6 +480,32 @@ void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, emitNote(Loc, Message.str(), &SM); } +void DiagnosticNoteRenderer::emitImportLocation(SourceLocation Loc, + PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) { + // Generate a note indicating the include location. + SmallString<200> MessageStorage; + llvm::raw_svector_ostream Message(MessageStorage); + Message << "in module '" << ModuleName << "' imported from " + << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; + emitNote(Loc, Message.str(), &SM); +} + +void +DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, + PresumedLoc PLoc, + StringRef ModuleName, + const SourceManager &SM) { + // Generate a note indicating the include location. + SmallString<200> MessageStorage; + llvm::raw_svector_ostream Message(MessageStorage); + Message << "while building module '" << ModuleName << "' imported from " + << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; + emitNote(Loc, Message.str(), &SM); +} + + void DiagnosticNoteRenderer::emitBasicNote(StringRef Message) { emitNote(SourceLocation(), Message, 0); } |