DiagnosticRenderer.cpp 24 KB

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