| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 1 | //===--- DiagnosticRenderer.cpp - Diagnostic Pretty-Printing --------------===// | 
|  | 2 | // | 
|  | 3 | //                     The LLVM Compiler Infrastructure | 
|  | 4 | // | 
|  | 5 | // This file is distributed under the University of Illinois Open Source | 
|  | 6 | // License. See LICENSE.TXT for details. | 
|  | 7 | // | 
|  | 8 | //===----------------------------------------------------------------------===// | 
|  | 9 |  | 
|  | 10 | #include "clang/Frontend/DiagnosticRenderer.h" | 
| Douglas Gregor | 811db4e | 2012-10-23 22:26:28 +0000 | [diff] [blame] | 11 | #include "clang/Basic/DiagnosticOptions.h" | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 12 | #include "clang/Basic/SourceManager.h" | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 13 | #include "clang/Edit/Commit.h" | 
| Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 14 | #include "clang/Edit/EditedSource.h" | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 15 | #include "clang/Edit/EditsReceiver.h" | 
| Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 16 | #include "clang/Lex/Lexer.h" | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/SmallSet.h" | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 18 | #include "llvm/ADT/SmallString.h" | 
| Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 19 | #include "llvm/Support/ErrorHandling.h" | 
| Chandler Carruth | 3a02247 | 2012-12-04 09:13:33 +0000 | [diff] [blame] | 20 | #include "llvm/Support/raw_ostream.h" | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 21 | #include <algorithm> | 
|  | 22 | using namespace clang; | 
|  | 23 |  | 
| Argyrios Kyrtzidis | b16ff5d | 2012-05-10 05:03:45 +0000 | [diff] [blame] | 24 | DiagnosticRenderer::DiagnosticRenderer(const LangOptions &LangOpts, | 
| Douglas Gregor | 811db4e | 2012-10-23 22:26:28 +0000 | [diff] [blame] | 25 | DiagnosticOptions *DiagOpts) | 
|  | 26 | : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {} | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 27 |  | 
| Angel Garcia Gomez | 637d1e6 | 2015-10-20 13:23:58 +0000 | [diff] [blame] | 28 | DiagnosticRenderer::~DiagnosticRenderer() {} | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 29 |  | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 30 | namespace { | 
|  | 31 |  | 
|  | 32 | class FixitReceiver : public edit::EditsReceiver { | 
|  | 33 | SmallVectorImpl<FixItHint> &MergedFixits; | 
|  | 34 |  | 
|  | 35 | public: | 
|  | 36 | FixitReceiver(SmallVectorImpl<FixItHint> &MergedFixits) | 
|  | 37 | : MergedFixits(MergedFixits) { } | 
| Craig Topper | afa7cb3 | 2014-03-13 06:07:04 +0000 | [diff] [blame] | 38 | void insert(SourceLocation loc, StringRef text) override { | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 39 | MergedFixits.push_back(FixItHint::CreateInsertion(loc, text)); | 
|  | 40 | } | 
| Craig Topper | afa7cb3 | 2014-03-13 06:07:04 +0000 | [diff] [blame] | 41 | void replace(CharSourceRange range, StringRef text) override { | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 42 | MergedFixits.push_back(FixItHint::CreateReplacement(range, text)); | 
|  | 43 | } | 
|  | 44 | }; | 
|  | 45 |  | 
| Alexander Kornienko | ab9db51 | 2015-06-22 23:07:51 +0000 | [diff] [blame] | 46 | } | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 47 |  | 
|  | 48 | static void mergeFixits(ArrayRef<FixItHint> FixItHints, | 
|  | 49 | const SourceManager &SM, const LangOptions &LangOpts, | 
|  | 50 | SmallVectorImpl<FixItHint> &MergedFixits) { | 
|  | 51 | edit::Commit commit(SM, LangOpts); | 
|  | 52 | for (ArrayRef<FixItHint>::const_iterator | 
|  | 53 | I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) { | 
|  | 54 | const FixItHint &Hint = *I; | 
|  | 55 | if (Hint.CodeToInsert.empty()) { | 
|  | 56 | if (Hint.InsertFromRange.isValid()) | 
|  | 57 | commit.insertFromRange(Hint.RemoveRange.getBegin(), | 
|  | 58 | Hint.InsertFromRange, /*afterToken=*/false, | 
|  | 59 | Hint.BeforePreviousInsertions); | 
|  | 60 | else | 
|  | 61 | commit.remove(Hint.RemoveRange); | 
|  | 62 | } else { | 
|  | 63 | if (Hint.RemoveRange.isTokenRange() || | 
|  | 64 | Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd()) | 
|  | 65 | commit.replace(Hint.RemoveRange, Hint.CodeToInsert); | 
|  | 66 | else | 
|  | 67 | commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert, | 
|  | 68 | /*afterToken=*/false, Hint.BeforePreviousInsertions); | 
|  | 69 | } | 
|  | 70 | } | 
|  | 71 |  | 
|  | 72 | edit::EditedSource Editor(SM, LangOpts); | 
|  | 73 | if (Editor.commit(commit)) { | 
|  | 74 | FixitReceiver Rec(MergedFixits); | 
|  | 75 | Editor.applyRewrites(Rec); | 
|  | 76 | } | 
|  | 77 | } | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 78 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 79 | void DiagnosticRenderer::emitDiagnostic(FullSourceLoc Loc, | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 80 | DiagnosticsEngine::Level Level, | 
|  | 81 | StringRef Message, | 
|  | 82 | ArrayRef<CharSourceRange> Ranges, | 
|  | 83 | ArrayRef<FixItHint> FixItHints, | 
| Ted Kremenek | 0964cca | 2012-02-14 02:46:00 +0000 | [diff] [blame] | 84 | DiagOrStoredDiag D) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 85 | assert(Loc.hasManager() || Loc.isInvalid()); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 86 |  | 
| Ted Kremenek | 0964cca | 2012-02-14 02:46:00 +0000 | [diff] [blame] | 87 | beginDiagnostic(D, Level); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 88 |  | 
|  | 89 | if (!Loc.isValid()) | 
|  | 90 | // If we have no source location, just emit the diagnostic message. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 91 | emitDiagnosticMessage(Loc, PresumedLoc(), Level, Message, Ranges, D); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 92 | else { | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 93 | // Get the ranges into a local array we can hack on. | 
|  | 94 | SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), | 
|  | 95 | Ranges.end()); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 96 |  | 
| Dmitri Gribenko | f857950 | 2013-01-12 19:30:44 +0000 | [diff] [blame] | 97 | SmallVector<FixItHint, 8> MergedFixits; | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 98 | if (!FixItHints.empty()) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 99 | mergeFixits(FixItHints, Loc.getManager(), LangOpts, MergedFixits); | 
| Ted Kremenek | f7639e1 | 2012-03-06 20:06:33 +0000 | [diff] [blame] | 100 | FixItHints = MergedFixits; | 
|  | 101 | } | 
|  | 102 |  | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 103 | for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(), | 
|  | 104 | E = FixItHints.end(); | 
|  | 105 | I != E; ++I) | 
|  | 106 | if (I->RemoveRange.isValid()) | 
|  | 107 | MutableRanges.push_back(I->RemoveRange); | 
| Richard Smith | aebee68 | 2012-12-05 06:20:58 +0000 | [diff] [blame] | 108 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 109 | FullSourceLoc UnexpandedLoc = Loc; | 
| Richard Smith | aebee68 | 2012-12-05 06:20:58 +0000 | [diff] [blame] | 110 |  | 
| Ted Kremenek | 372735f | 2012-12-19 01:16:49 +0000 | [diff] [blame] | 111 | // Find the ultimate expansion location for the diagnostic. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 112 | Loc = Loc.getFileLoc(); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 113 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 114 | PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 115 |  | 
|  | 116 | // First, if this diagnostic is not in the main file, print out the | 
|  | 117 | // "included from" lines. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 118 | emitIncludeStack(Loc, PLoc, Level); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 119 |  | 
|  | 120 | // Next, emit the actual diagnostic message and caret. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 121 | emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, D); | 
|  | 122 | emitCaret(Loc, Level, MutableRanges, FixItHints); | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 123 |  | 
|  | 124 | // If this location is within a macro, walk from UnexpandedLoc up to Loc | 
|  | 125 | // and produce a macro backtrace. | 
|  | 126 | if (UnexpandedLoc.isValid() && UnexpandedLoc.isMacroID()) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 127 | emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints); | 
| Richard Smith | aebee68 | 2012-12-05 06:20:58 +0000 | [diff] [blame] | 128 | } | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 129 | } | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 130 |  | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 131 | LastLoc = Loc; | 
|  | 132 | LastLevel = Level; | 
| Richard Smith | c01cca2 | 2012-12-05 09:47:49 +0000 | [diff] [blame] | 133 |  | 
| Ted Kremenek | 0964cca | 2012-02-14 02:46:00 +0000 | [diff] [blame] | 134 | endDiagnostic(D, Level); | 
|  | 135 | } | 
|  | 136 |  | 
|  | 137 |  | 
|  | 138 | void DiagnosticRenderer::emitStoredDiagnostic(StoredDiagnostic &Diag) { | 
|  | 139 | emitDiagnostic(Diag.getLocation(), Diag.getLevel(), Diag.getMessage(), | 
|  | 140 | Diag.getRanges(), Diag.getFixIts(), | 
|  | 141 | &Diag); | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 142 | } | 
|  | 143 |  | 
| Alp Toker | 4db87ab | 2014-06-21 23:31:59 +0000 | [diff] [blame] | 144 | void DiagnosticRenderer::emitBasicNote(StringRef Message) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 145 | emitDiagnosticMessage(FullSourceLoc(), PresumedLoc(), DiagnosticsEngine::Note, | 
|  | 146 | Message, None, DiagOrStoredDiag()); | 
| Alp Toker | 4db87ab | 2014-06-21 23:31:59 +0000 | [diff] [blame] | 147 | } | 
|  | 148 |  | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 149 | /// \brief Prints an include stack when appropriate for a particular | 
|  | 150 | /// diagnostic level and location. | 
|  | 151 | /// | 
|  | 152 | /// This routine handles all the logic of suppressing particular include | 
|  | 153 | /// stacks (such as those for notes) and duplicate include stacks when | 
|  | 154 | /// repeated warnings occur within the same file. It also handles the logic | 
|  | 155 | /// of customizing the formatting and display of the include stack. | 
|  | 156 | /// | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 157 | /// \param Loc   The diagnostic location. | 
|  | 158 | /// \param PLoc  The presumed location of the diagnostic location. | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 159 | /// \param Level The diagnostic level of the message this stack pertains to. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 160 | void DiagnosticRenderer::emitIncludeStack(FullSourceLoc Loc, PresumedLoc PLoc, | 
|  | 161 | DiagnosticsEngine::Level Level) { | 
|  | 162 | FullSourceLoc IncludeLoc = | 
|  | 163 | PLoc.isInvalid() ? FullSourceLoc() | 
|  | 164 | : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager()); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 165 |  | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 166 | // Skip redundant include stacks altogether. | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 167 | if (LastIncludeLoc == IncludeLoc) | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 168 | return; | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 169 |  | 
|  | 170 | LastIncludeLoc = IncludeLoc; | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 171 |  | 
| Douglas Gregor | 811db4e | 2012-10-23 22:26:28 +0000 | [diff] [blame] | 172 | if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 173 | return; | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 174 |  | 
|  | 175 | if (IncludeLoc.isValid()) | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 176 | emitIncludeStackRecursively(IncludeLoc); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 177 | else { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 178 | emitModuleBuildStack(Loc.getManager()); | 
|  | 179 | emitImportStack(Loc); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 180 | } | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 181 | } | 
|  | 182 |  | 
|  | 183 | /// \brief Helper to recursivly walk up the include stack and print each layer | 
|  | 184 | /// on the way back down. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 185 | void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) { | 
| Douglas Gregor | af8f026 | 2012-11-30 18:38:50 +0000 | [diff] [blame] | 186 | if (Loc.isInvalid()) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 187 | emitModuleBuildStack(Loc.getManager()); | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 188 | return; | 
| Douglas Gregor | af8f026 | 2012-11-30 18:38:50 +0000 | [diff] [blame] | 189 | } | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 190 |  | 
|  | 191 | PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 192 | if (PLoc.isInvalid()) | 
|  | 193 | return; | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 194 |  | 
|  | 195 | // If this source location was imported from a module, print the module | 
|  | 196 | // import stack rather than the | 
|  | 197 | // FIXME: We want submodule granularity here. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 198 | std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc(); | 
| Richard Smith | a24ff55 | 2015-08-11 00:05:21 +0000 | [diff] [blame] | 199 | if (!Imported.second.empty()) { | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 200 | // This location was imported by a module. Emit the module import stack. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 201 | emitImportStackRecursively(Imported.first, Imported.second); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 202 | return; | 
|  | 203 | } | 
|  | 204 |  | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 205 | // Emit the other include frames first. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 206 | emitIncludeStackRecursively( | 
|  | 207 | FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager())); | 
|  | 208 |  | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 209 | // Emit the inclusion text/note. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 210 | emitIncludeLocation(Loc, PLoc); | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 211 | } | 
|  | 212 |  | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 213 | /// \brief Emit the module import stack associated with the current location. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 214 | void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) { | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 215 | if (Loc.isInvalid()) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 216 | emitModuleBuildStack(Loc.getManager()); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 217 | return; | 
|  | 218 | } | 
|  | 219 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 220 | std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); | 
|  | 221 | emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 222 | } | 
|  | 223 |  | 
|  | 224 | /// \brief Helper to recursivly walk up the import stack and print each layer | 
|  | 225 | /// on the way back down. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 226 | void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc, | 
|  | 227 | StringRef ModuleName) { | 
| Richard Smith | a24ff55 | 2015-08-11 00:05:21 +0000 | [diff] [blame] | 228 | if (ModuleName.empty()) { | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 229 | return; | 
|  | 230 | } | 
|  | 231 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 232 | PresumedLoc PLoc = Loc.getPresumedLoc(DiagOpts->ShowPresumedLoc); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 233 |  | 
|  | 234 | // Emit the other import frames first. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 235 | std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc(); | 
|  | 236 | emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 237 |  | 
|  | 238 | // Emit the inclusion text/note. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 239 | emitImportLocation(Loc, PLoc, ModuleName); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 240 | } | 
|  | 241 |  | 
| Douglas Gregor | 6336543 | 2012-11-30 22:11:57 +0000 | [diff] [blame] | 242 | /// \brief Emit the module build stack, for cases where a module is (re-)built | 
| Douglas Gregor | af8f026 | 2012-11-30 18:38:50 +0000 | [diff] [blame] | 243 | /// on demand. | 
| Douglas Gregor | 6336543 | 2012-11-30 22:11:57 +0000 | [diff] [blame] | 244 | void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) { | 
|  | 245 | ModuleBuildStack Stack = SM.getModuleBuildStack(); | 
|  | 246 | for (unsigned I = 0, N = Stack.size(); I != N; ++I) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 247 | emitBuildingModuleLocation(Stack[I].second, Stack[I].second.getPresumedLoc( | 
| Douglas Gregor | af8f026 | 2012-11-30 18:38:50 +0000 | [diff] [blame] | 248 | DiagOpts->ShowPresumedLoc), | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 249 | Stack[I].first); | 
| Douglas Gregor | af8f026 | 2012-11-30 18:38:50 +0000 | [diff] [blame] | 250 | } | 
|  | 251 | } | 
|  | 252 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 253 | /// A recursive function to trace all possible backtrace locations | 
|  | 254 | /// to match the \p CaretLocFileID. | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 255 | static SourceLocation | 
|  | 256 | retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID, | 
|  | 257 | FileID CaretFileID, | 
|  | 258 | const SmallVectorImpl<FileID> &CommonArgExpansions, | 
|  | 259 | bool IsBegin, const SourceManager *SM) { | 
|  | 260 | assert(SM->getFileID(Loc) == MacroFileID); | 
|  | 261 | if (MacroFileID == CaretFileID) | 
|  | 262 | return Loc; | 
|  | 263 | if (!Loc.isMacroID()) | 
|  | 264 | return SourceLocation(); | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 265 |  | 
|  | 266 | SourceLocation MacroLocation, MacroArgLocation; | 
|  | 267 |  | 
|  | 268 | if (SM->isMacroArgExpansion(Loc)) { | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 269 | // Only look at the immediate spelling location of this macro argument if | 
|  | 270 | // the other location in the source range is also present in that expansion. | 
|  | 271 | if (std::binary_search(CommonArgExpansions.begin(), | 
|  | 272 | CommonArgExpansions.end(), MacroFileID)) | 
|  | 273 | MacroLocation = SM->getImmediateSpellingLoc(Loc); | 
|  | 274 | MacroArgLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first | 
|  | 275 | : SM->getImmediateExpansionRange(Loc).second; | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 276 | } else { | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 277 | MacroLocation = IsBegin ? SM->getImmediateExpansionRange(Loc).first | 
|  | 278 | : SM->getImmediateExpansionRange(Loc).second; | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 279 | MacroArgLocation = SM->getImmediateSpellingLoc(Loc); | 
|  | 280 | } | 
|  | 281 |  | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 282 | if (MacroLocation.isValid()) { | 
|  | 283 | MacroFileID = SM->getFileID(MacroLocation); | 
|  | 284 | MacroLocation = | 
|  | 285 | retrieveMacroLocation(MacroLocation, MacroFileID, CaretFileID, | 
|  | 286 | CommonArgExpansions, IsBegin, SM); | 
|  | 287 | if (MacroLocation.isValid()) | 
|  | 288 | return MacroLocation; | 
|  | 289 | } | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 290 |  | 
|  | 291 | MacroFileID = SM->getFileID(MacroArgLocation); | 
|  | 292 | return retrieveMacroLocation(MacroArgLocation, MacroFileID, CaretFileID, | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 293 | CommonArgExpansions, IsBegin, SM); | 
|  | 294 | } | 
|  | 295 |  | 
|  | 296 | /// Walk up the chain of macro expansions and collect the FileIDs identifying the | 
|  | 297 | /// expansions. | 
|  | 298 | static void getMacroArgExpansionFileIDs(SourceLocation Loc, | 
|  | 299 | SmallVectorImpl<FileID> &IDs, | 
|  | 300 | bool IsBegin, const SourceManager *SM) { | 
|  | 301 | while (Loc.isMacroID()) { | 
|  | 302 | if (SM->isMacroArgExpansion(Loc)) { | 
|  | 303 | IDs.push_back(SM->getFileID(Loc)); | 
|  | 304 | Loc = SM->getImmediateSpellingLoc(Loc); | 
|  | 305 | } else { | 
|  | 306 | auto ExpRange = SM->getImmediateExpansionRange(Loc); | 
|  | 307 | Loc = IsBegin ? ExpRange.first : ExpRange.second; | 
|  | 308 | } | 
|  | 309 | } | 
|  | 310 | } | 
|  | 311 |  | 
|  | 312 | /// Collect the expansions of the begin and end locations and compute the set | 
|  | 313 | /// intersection. Produces a sorted vector of FileIDs in CommonArgExpansions. | 
|  | 314 | static void computeCommonMacroArgExpansionFileIDs( | 
|  | 315 | SourceLocation Begin, SourceLocation End, const SourceManager *SM, | 
|  | 316 | SmallVectorImpl<FileID> &CommonArgExpansions) { | 
|  | 317 | SmallVector<FileID, 4> BeginArgExpansions; | 
|  | 318 | SmallVector<FileID, 4> EndArgExpansions; | 
|  | 319 | getMacroArgExpansionFileIDs(Begin, BeginArgExpansions, /*IsBegin=*/true, SM); | 
|  | 320 | getMacroArgExpansionFileIDs(End, EndArgExpansions, /*IsBegin=*/false, SM); | 
|  | 321 | std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end()); | 
|  | 322 | std::sort(EndArgExpansions.begin(), EndArgExpansions.end()); | 
|  | 323 | std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(), | 
|  | 324 | EndArgExpansions.begin(), EndArgExpansions.end(), | 
|  | 325 | std::back_inserter(CommonArgExpansions)); | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 326 | } | 
|  | 327 |  | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 328 | // Helper function to fix up source ranges.  It takes in an array of ranges, | 
|  | 329 | // and outputs an array of ranges where we want to draw the range highlighting | 
|  | 330 | // around the location specified by CaretLoc. | 
|  | 331 | // | 
|  | 332 | // To find locations which correspond to the caret, we crawl the macro caller | 
|  | 333 | // chain for the beginning and end of each range.  If the caret location | 
|  | 334 | // is in a macro expansion, we search each chain for a location | 
|  | 335 | // in the same expansion as the caret; otherwise, we crawl to the top of | 
|  | 336 | // each chain. Two locations are part of the same macro expansion | 
|  | 337 | // iff the FileID is the same. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 338 | static void | 
|  | 339 | mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef<CharSourceRange> Ranges, | 
|  | 340 | SmallVectorImpl<CharSourceRange> &SpellingRanges) { | 
|  | 341 | FileID CaretLocFileID = CaretLoc.getFileID(); | 
|  | 342 |  | 
|  | 343 | const SourceManager *SM = &CaretLoc.getManager(); | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 344 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 345 | for (auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) { | 
|  | 346 | if (I->isInvalid()) continue; | 
|  | 347 |  | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 348 | SourceLocation Begin = I->getBegin(), End = I->getEnd(); | 
|  | 349 | bool IsTokenRange = I->isTokenRange(); | 
|  | 350 |  | 
| Eli Friedman | dea98de | 2012-11-30 06:19:40 +0000 | [diff] [blame] | 351 | FileID BeginFileID = SM->getFileID(Begin); | 
| Nadav Rotem | b893734 | 2012-12-13 19:58:10 +0000 | [diff] [blame] | 352 | FileID EndFileID = SM->getFileID(End); | 
| Eli Friedman | dea98de | 2012-11-30 06:19:40 +0000 | [diff] [blame] | 353 |  | 
| Nadav Rotem | b893734 | 2012-12-13 19:58:10 +0000 | [diff] [blame] | 354 | // Find the common parent for the beginning and end of the range. | 
|  | 355 |  | 
|  | 356 | // First, crawl the expansion chain for the beginning of the range. | 
|  | 357 | llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap; | 
|  | 358 | while (Begin.isMacroID() && BeginFileID != EndFileID) { | 
|  | 359 | BeginLocsMap[BeginFileID] = Begin; | 
|  | 360 | Begin = SM->getImmediateExpansionRange(Begin).first; | 
|  | 361 | BeginFileID = SM->getFileID(Begin); | 
|  | 362 | } | 
|  | 363 |  | 
|  | 364 | // Then, crawl the expansion chain for the end of the range. | 
|  | 365 | if (BeginFileID != EndFileID) { | 
|  | 366 | while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) { | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 367 | End = SM->getImmediateExpansionRange(End).second; | 
| Nadav Rotem | b893734 | 2012-12-13 19:58:10 +0000 | [diff] [blame] | 368 | EndFileID = SM->getFileID(End); | 
|  | 369 | } | 
|  | 370 | if (End.isMacroID()) { | 
|  | 371 | Begin = BeginLocsMap[EndFileID]; | 
|  | 372 | BeginFileID = EndFileID; | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 373 | } | 
| Eli Friedman | cdb135a | 2012-12-13 00:14:59 +0000 | [diff] [blame] | 374 | } | 
|  | 375 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 376 | // Do the backtracking. | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 377 | SmallVector<FileID, 4> CommonArgExpansions; | 
|  | 378 | computeCommonMacroArgExpansionFileIDs(Begin, End, SM, CommonArgExpansions); | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 379 | Begin = retrieveMacroLocation(Begin, BeginFileID, CaretLocFileID, | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 380 | CommonArgExpansions, /*IsBegin=*/true, SM); | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 381 | End = retrieveMacroLocation(End, BeginFileID, CaretLocFileID, | 
| Reid Kleckner | da30cff | 2015-12-08 01:08:09 +0000 | [diff] [blame] | 382 | CommonArgExpansions, /*IsBegin=*/false, SM); | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 383 | if (Begin.isInvalid() || End.isInvalid()) continue; | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 384 |  | 
|  | 385 | // Return the spelling location of the beginning and end of the range. | 
|  | 386 | Begin = SM->getSpellingLoc(Begin); | 
|  | 387 | End = SM->getSpellingLoc(End); | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 388 |  | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 389 | SpellingRanges.push_back(CharSourceRange(SourceRange(Begin, End), | 
|  | 390 | IsTokenRange)); | 
|  | 391 | } | 
|  | 392 | } | 
|  | 393 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 394 | void DiagnosticRenderer::emitCaret(FullSourceLoc Loc, | 
| Richard Smith | aebee68 | 2012-12-05 06:20:58 +0000 | [diff] [blame] | 395 | DiagnosticsEngine::Level Level, | 
|  | 396 | ArrayRef<CharSourceRange> Ranges, | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 397 | ArrayRef<FixItHint> Hints) { | 
| Richard Smith | aebee68 | 2012-12-05 06:20:58 +0000 | [diff] [blame] | 398 | SmallVector<CharSourceRange, 4> SpellingRanges; | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 399 | mapDiagnosticRanges(Loc, Ranges, SpellingRanges); | 
|  | 400 | emitCodeContext(Loc, Level, SpellingRanges, Hints); | 
| Richard Smith | aebee68 | 2012-12-05 06:20:58 +0000 | [diff] [blame] | 401 | } | 
|  | 402 |  | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 403 | /// \brief A helper function for emitMacroExpansion to print the | 
|  | 404 | /// macro expansion message | 
|  | 405 | void DiagnosticRenderer::emitSingleMacroExpansion( | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 406 | FullSourceLoc Loc, DiagnosticsEngine::Level Level, | 
|  | 407 | ArrayRef<CharSourceRange> Ranges) { | 
| Richard Smith | 7a2d40d | 2012-12-05 03:18:16 +0000 | [diff] [blame] | 408 | // Find the spelling location for the macro definition. We must use the | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 409 | // spelling location here to avoid emitting a macro backtrace for the note. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 410 | FullSourceLoc SpellingLoc = Loc.getSpellingLoc(); | 
| Richard Smith | 7a2d40d | 2012-12-05 03:18:16 +0000 | [diff] [blame] | 411 |  | 
|  | 412 | // Map the ranges into the FileID of the diagnostic location. | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 413 | SmallVector<CharSourceRange, 4> SpellingRanges; | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 414 | mapDiagnosticRanges(Loc, Ranges, SpellingRanges); | 
| Eli Friedman | 34ff0ea | 2012-11-03 03:36:51 +0000 | [diff] [blame] | 415 |  | 
| Dylan Noblesmith | 2c1dd27 | 2012-02-05 02:13:05 +0000 | [diff] [blame] | 416 | SmallString<100> MessageStorage; | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 417 | llvm::raw_svector_ostream Message(MessageStorage); | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 418 | StringRef MacroName = Lexer::getImmediateMacroNameForDiagnostics( | 
|  | 419 | Loc, Loc.getManager(), LangOpts); | 
| Richard Smith | f89e2e2 | 2012-12-05 11:04:55 +0000 | [diff] [blame] | 420 | if (MacroName.empty()) | 
|  | 421 | Message << "expanded from here"; | 
|  | 422 | else | 
|  | 423 | Message << "expanded from macro '" << MacroName << "'"; | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 424 |  | 
| Dmitri Gribenko | 44ebbd5 | 2013-05-05 00:41:58 +0000 | [diff] [blame] | 425 | emitDiagnostic(SpellingLoc, DiagnosticsEngine::Note, Message.str(), | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 426 | SpellingRanges, None); | 
| Ted Kremenek | c4bbd85 | 2011-12-17 05:26:04 +0000 | [diff] [blame] | 427 | } | 
|  | 428 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 429 | /// Check that the macro argument location of Loc starts with ArgumentLoc. | 
|  | 430 | /// The starting location of the macro expansions is used to differeniate | 
|  | 431 | /// different macro expansions. | 
|  | 432 | static bool checkLocForMacroArgExpansion(SourceLocation Loc, | 
|  | 433 | const SourceManager &SM, | 
|  | 434 | SourceLocation ArgumentLoc) { | 
|  | 435 | SourceLocation MacroLoc; | 
|  | 436 | if (SM.isMacroArgExpansion(Loc, &MacroLoc)) { | 
|  | 437 | if (ArgumentLoc == MacroLoc) return true; | 
|  | 438 | } | 
|  | 439 |  | 
|  | 440 | return false; | 
|  | 441 | } | 
|  | 442 |  | 
|  | 443 | /// Check if all the locations in the range have the same macro argument | 
|  | 444 | /// expansion, and that that expansion starts with ArgumentLoc. | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 445 | static bool checkRangeForMacroArgExpansion(CharSourceRange Range, | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 446 | const SourceManager &SM, | 
|  | 447 | SourceLocation ArgumentLoc) { | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 448 | SourceLocation BegLoc = Range.getBegin(), EndLoc = Range.getEnd(); | 
|  | 449 | while (BegLoc != EndLoc) { | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 450 | if (!checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc)) | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 451 | return false; | 
|  | 452 | BegLoc.getLocWithOffset(1); | 
|  | 453 | } | 
|  | 454 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 455 | return checkLocForMacroArgExpansion(BegLoc, SM, ArgumentLoc); | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 456 | } | 
|  | 457 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 458 | /// A helper function to check if the current ranges are all inside the same | 
|  | 459 | /// macro argument expansion as Loc. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 460 | static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc, | 
|  | 461 | ArrayRef<CharSourceRange> Ranges) { | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 462 | assert(Loc.isMacroID() && "Must be a macro expansion!"); | 
|  | 463 |  | 
|  | 464 | SmallVector<CharSourceRange, 4> SpellingRanges; | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 465 | mapDiagnosticRanges(Loc, Ranges, SpellingRanges); | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 466 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 467 | /// Count all valid ranges. | 
|  | 468 | unsigned ValidCount = 0; | 
|  | 469 | for (auto I : Ranges) | 
|  | 470 | if (I.isValid()) ValidCount++; | 
|  | 471 |  | 
|  | 472 | if (ValidCount > SpellingRanges.size()) | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 473 | return false; | 
|  | 474 |  | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 475 | /// To store the source location of the argument location. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 476 | FullSourceLoc ArgumentLoc; | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 477 |  | 
|  | 478 | /// Set the ArgumentLoc to the beginning location of the expansion of Loc | 
|  | 479 | /// so to check if the ranges expands to the same beginning location. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 480 | if (!Loc.isMacroArgExpansion(&ArgumentLoc)) | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 481 | return false; | 
|  | 482 |  | 
|  | 483 | for (auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) { | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 484 | if (!checkRangeForMacroArgExpansion(*I, Loc.getManager(), ArgumentLoc)) | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 485 | return false; | 
| Richard Trieu | c309624 | 2015-09-24 01:21:01 +0000 | [diff] [blame] | 486 | } | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 487 |  | 
|  | 488 | return true; | 
|  | 489 | } | 
|  | 490 |  | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 491 | /// \brief Recursively emit notes for each macro expansion and caret | 
|  | 492 | /// diagnostics where appropriate. | 
|  | 493 | /// | 
|  | 494 | /// Walks up the macro expansion stack printing expansion notes, the code | 
|  | 495 | /// snippet, caret, underlines and FixItHint display as appropriate at each | 
|  | 496 | /// level. | 
|  | 497 | /// | 
|  | 498 | /// \param Loc The location for this caret. | 
|  | 499 | /// \param Level The diagnostic level currently being emitted. | 
|  | 500 | /// \param Ranges The underlined ranges for this code snippet. | 
|  | 501 | /// \param Hints The FixIt hints active for this diagnostic. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 502 | void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc, | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 503 | DiagnosticsEngine::Level Level, | 
|  | 504 | ArrayRef<CharSourceRange> Ranges, | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 505 | ArrayRef<FixItHint> Hints) { | 
| Yaron Keren | ed1fe5d | 2015-10-03 05:15:57 +0000 | [diff] [blame] | 506 | assert(Loc.isValid() && "must have a valid source location here"); | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 507 |  | 
|  | 508 | // Produce a stack of macro backtraces. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 509 | SmallVector<FullSourceLoc, 8> LocationStack; | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 510 | unsigned IgnoredEnd = 0; | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 511 | while (Loc.isMacroID()) { | 
| Richard Trieu | a1d7ece | 2015-08-27 23:38:45 +0000 | [diff] [blame] | 512 | // If this is the expansion of a macro argument, point the caret at the | 
|  | 513 | // use of the argument in the definition of the macro, not the expansion. | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 514 | if (Loc.isMacroArgExpansion()) | 
|  | 515 | LocationStack.push_back(Loc.getImmediateExpansionRange().first); | 
| Richard Trieu | a1d7ece | 2015-08-27 23:38:45 +0000 | [diff] [blame] | 516 | else | 
|  | 517 | LocationStack.push_back(Loc); | 
|  | 518 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 519 | if (checkRangesForMacroArgExpansion(Loc, Ranges)) | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 520 | IgnoredEnd = LocationStack.size(); | 
|  | 521 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 522 | Loc = Loc.getImmediateMacroCallerLoc(); | 
| Richard Trieu | a1d7ece | 2015-08-27 23:38:45 +0000 | [diff] [blame] | 523 |  | 
|  | 524 | // Once the location no longer points into a macro, try stepping through | 
|  | 525 | // the last found location.  This sometimes produces additional useful | 
|  | 526 | // backtraces. | 
|  | 527 | if (Loc.isFileID()) | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 528 | Loc = LocationStack.back().getImmediateMacroCallerLoc(); | 
| Yaron Keren | ed1fe5d | 2015-10-03 05:15:57 +0000 | [diff] [blame] | 529 | assert(Loc.isValid() && "must have a valid source location here"); | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 530 | } | 
|  | 531 |  | 
| Richard Trieu | ecd36ee | 2015-08-12 18:24:59 +0000 | [diff] [blame] | 532 | LocationStack.erase(LocationStack.begin(), | 
|  | 533 | LocationStack.begin() + IgnoredEnd); | 
|  | 534 |  | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 535 | unsigned MacroDepth = LocationStack.size(); | 
|  | 536 | unsigned MacroLimit = DiagOpts->MacroBacktraceLimit; | 
|  | 537 | if (MacroDepth <= MacroLimit || MacroLimit == 0) { | 
|  | 538 | for (auto I = LocationStack.rbegin(), E = LocationStack.rend(); | 
|  | 539 | I != E; ++I) | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 540 | emitSingleMacroExpansion(*I, Level, Ranges); | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 541 | return; | 
|  | 542 | } | 
|  | 543 |  | 
|  | 544 | unsigned MacroStartMessages = MacroLimit / 2; | 
|  | 545 | unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2; | 
|  | 546 |  | 
|  | 547 | for (auto I = LocationStack.rbegin(), | 
|  | 548 | E = LocationStack.rbegin() + MacroStartMessages; | 
|  | 549 | I != E; ++I) | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 550 | emitSingleMacroExpansion(*I, Level, Ranges); | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 551 |  | 
|  | 552 | SmallString<200> MessageStorage; | 
|  | 553 | llvm::raw_svector_ostream Message(MessageStorage); | 
|  | 554 | Message << "(skipping " << (MacroDepth - MacroLimit) | 
|  | 555 | << " expansions in backtrace; use -fmacro-backtrace-limit=0 to " | 
|  | 556 | "see all)"; | 
|  | 557 | emitBasicNote(Message.str()); | 
|  | 558 |  | 
|  | 559 | for (auto I = LocationStack.rend() - MacroEndMessages, | 
|  | 560 | E = LocationStack.rend(); | 
|  | 561 | I != E; ++I) | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 562 | emitSingleMacroExpansion(*I, Level, Ranges); | 
| Richard Trieu | 97c45b6 | 2015-07-28 20:53:46 +0000 | [diff] [blame] | 563 | } | 
|  | 564 |  | 
| Angel Garcia Gomez | 637d1e6 | 2015-10-20 13:23:58 +0000 | [diff] [blame] | 565 | DiagnosticNoteRenderer::~DiagnosticNoteRenderer() {} | 
| Ted Kremenek | 0964cca | 2012-02-14 02:46:00 +0000 | [diff] [blame] | 566 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 567 | void DiagnosticNoteRenderer::emitIncludeLocation(FullSourceLoc Loc, | 
|  | 568 | PresumedLoc PLoc) { | 
| Ted Kremenek | 0964cca | 2012-02-14 02:46:00 +0000 | [diff] [blame] | 569 | // Generate a note indicating the include location. | 
|  | 570 | SmallString<200> MessageStorage; | 
|  | 571 | llvm::raw_svector_ostream Message(MessageStorage); | 
|  | 572 | Message << "in file included from " << PLoc.getFilename() << ':' | 
|  | 573 | << PLoc.getLine() << ":"; | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 574 | emitNote(Loc, Message.str()); | 
| Ted Kremenek | 0964cca | 2012-02-14 02:46:00 +0000 | [diff] [blame] | 575 | } | 
|  | 576 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 577 | void DiagnosticNoteRenderer::emitImportLocation(FullSourceLoc Loc, | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 578 | PresumedLoc PLoc, | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 579 | StringRef ModuleName) { | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 580 | // Generate a note indicating the include location. | 
|  | 581 | SmallString<200> MessageStorage; | 
|  | 582 | llvm::raw_svector_ostream Message(MessageStorage); | 
| Richard Smith | a24ff55 | 2015-08-11 00:05:21 +0000 | [diff] [blame] | 583 | Message << "in module '" << ModuleName; | 
| Yaron Keren | ed1fe5d | 2015-10-03 05:15:57 +0000 | [diff] [blame] | 584 | if (PLoc.isValid()) | 
| Richard Smith | a24ff55 | 2015-08-11 00:05:21 +0000 | [diff] [blame] | 585 | Message << "' imported from " << PLoc.getFilename() << ':' | 
|  | 586 | << PLoc.getLine(); | 
|  | 587 | Message << ":"; | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 588 | emitNote(Loc, Message.str()); | 
| Douglas Gregor | 22103e3 | 2012-11-30 21:58:49 +0000 | [diff] [blame] | 589 | } | 
|  | 590 |  | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 591 | void DiagnosticNoteRenderer::emitBuildingModuleLocation(FullSourceLoc Loc, | 
|  | 592 | PresumedLoc PLoc, | 
|  | 593 | StringRef ModuleName) { | 
| Douglas Gregor | af8f026 | 2012-11-30 18:38:50 +0000 | [diff] [blame] | 594 | // Generate a note indicating the include location. | 
|  | 595 | SmallString<200> MessageStorage; | 
|  | 596 | llvm::raw_svector_ostream Message(MessageStorage); | 
| Jordan Rose | 602ac14 | 2016-06-28 01:02:31 +0000 | [diff] [blame] | 597 | if (PLoc.isValid()) | 
| Richard Smith | 7bea1d4 | 2014-03-05 20:55:36 +0000 | [diff] [blame] | 598 | Message << "while building module '" << ModuleName << "' imported from " | 
|  | 599 | << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; | 
|  | 600 | else | 
| Jordan Rose | 6dcdaa6 | 2014-07-26 01:22:02 +0000 | [diff] [blame] | 601 | Message << "while building module '" << ModuleName << "':"; | 
| Christof Douma | fb4a045 | 2017-06-27 09:50:38 +0000 | [diff] [blame] | 602 | emitNote(Loc, Message.str()); | 
| Douglas Gregor | af8f026 | 2012-11-30 18:38:50 +0000 | [diff] [blame] | 603 | } |