DiagnosticRenderer.cpp 24 KB

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