clang: lib/Frontend/DiagnosticRenderer.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

19#include "llvm/ADT/ArrayRef.h"

20#include "llvm/ADT/DenseMap.h"

21#include "llvm/ADT/SmallVector.h"

22#include "llvm/ADT/StringRef.h"

23#include "llvm/Support/raw_ostream.h"

24#include

25#include

26#include

27#include

28

29using namespace clang;

30

34

36

37namespace {

38

41

42public:

44 : MergedFixits(MergedFixits) {}

45

46 void insert(SourceLocation loc, StringRef text) override {

48 }

49

50 void replace(CharSourceRange range, StringRef text) override {

52 }

53};

54

55}

56

61 for (const auto &Hint : FixItHints)

62 if (Hint.CodeToInsert.empty()) {

63 if (Hint.InsertFromRange.isValid())

65 Hint.InsertFromRange, false,

66 Hint.BeforePreviousInsertions);

67 else

68 commit.remove(Hint.RemoveRange);

69 } else {

70 if (Hint.RemoveRange.isTokenRange() ||

71 Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())

72 commit.replace(Hint.RemoveRange, Hint.CodeToInsert);

73 else

74 commit.insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,

75 false, Hint.BeforePreviousInsertions);

76 }

77

79 if (Editor.commit(commit)) {

80 FixitReceiver Rec(MergedFixits);

82 }

83}

84

87 StringRef Message,

92

94

96

98 else {

99

101

103 if (!FixItHints.empty()) {

105 FixItHints = MergedFixits;

106 }

107

108 for (const auto &Hint : FixItHints)

109 if (Hint.RemoveRange.isValid())

110 MutableRanges.push_back(Hint.RemoveRange);

111

113

114

116

118

119

120

121 emitIncludeStack(Loc, PLoc, Level);

122

123

125 emitCaret(Loc, Level, MutableRanges, FixItHints);

126

127

128

130 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);

131 }

132 }

133

136

138}

139

142 Diag.getRanges(), Diag.getFixIts(),

144}

145

146void DiagnosticRenderer::emitBasicNote(StringRef Message) {

149}

150

151

152

153

154

155

156

157

158

159

160

161

164 FullSourceLoc IncludeLoc =

165 PLoc.isInvalid() ? FullSourceLoc()

166 : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());

167

168

170 return;

171

173

175 return;

176

178 emitIncludeStackRecursively(IncludeLoc);

179 else {

180 emitModuleBuildStack(Loc.getManager());

181 emitImportStack(Loc);

182 }

183}

184

185

186

187void DiagnosticRenderer::emitIncludeStackRecursively(FullSourceLoc Loc) {

189 emitModuleBuildStack(Loc.getManager());

190 return;

191 }

192

195 return;

196

197

198

199

200 std::pair<FullSourceLoc, StringRef> Imported = Loc.getModuleImportLoc();

201 if (!Imported.second.empty()) {

202

203 emitImportStackRecursively(Imported.first, Imported.second);

204 return;

205 }

206

207

208 emitIncludeStackRecursively(

210

211

213}

214

215

216void DiagnosticRenderer::emitImportStack(FullSourceLoc Loc) {

218 emitModuleBuildStack(Loc.getManager());

219 return;

220 }

221

222 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();

223 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);

224}

225

226

227

228void DiagnosticRenderer::emitImportStackRecursively(FullSourceLoc Loc,

229 StringRef ModuleName) {

230 if (ModuleName.empty()) {

231 return;

232 }

233

235

236

237 std::pair<FullSourceLoc, StringRef> NextImportLoc = Loc.getModuleImportLoc();

238 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);

239

240

242}

243

244

245

246void DiagnosticRenderer::emitModuleBuildStack(const SourceManager &SM) {

248 for (const auto &I : Stack) {

250 I.second, I.second.getPresumedLoc(DiagOpts.ShowPresumedLoc), I.first);

251 }

252}

253

254

255

261 bool &IsTokenRange) {

262 assert(SM->getFileID(Loc) == MacroFileID);

263 if (MacroFileID == CaretFileID)

264 return Loc;

266 return {};

267

269

270 if (SM->isMacroArgExpansion(Loc)) {

271

272

273 if (llvm::binary_search(CommonArgExpansions, MacroFileID))

274 MacroRange =

276 MacroArgRange = SM->getImmediateExpansionRange(Loc);

277 } else {

278 MacroRange = SM->getImmediateExpansionRange(Loc);

279 MacroArgRange =

281 }

282

284 IsBegin ? MacroRange.getBegin() : MacroRange.getEnd();

285 if (MacroLocation.isValid()) {

286 MacroFileID = SM->getFileID(MacroLocation);

287 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.isTokenRange();

288 MacroLocation =

290 CommonArgExpansions, IsBegin, SM, TokenRange);

291 if (MacroLocation.isValid()) {

292 IsTokenRange = TokenRange;

293 return MacroLocation;

294 }

295 }

296

297

298

299 if (!IsBegin)

301

303 IsBegin ? MacroArgRange.getBegin() : MacroArgRange.getEnd();

304 MacroFileID = SM->getFileID(MacroArgLocation);

306 CommonArgExpansions, IsBegin, SM, IsTokenRange);

307}

308

309

310

315 if (SM->isMacroArgExpansion(Loc)) {

316 IDs.push_back(SM->getFileID(Loc));

317 Loc = SM->getImmediateSpellingLoc(Loc);

318 } else {

319 auto ExpRange = SM->getImmediateExpansionRange(Loc);

320 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();

321 }

322 }

323}

324

325

326

334 llvm::sort(BeginArgExpansions);

335 llvm::sort(EndArgExpansions);

336 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),

337 EndArgExpansions.begin(), EndArgExpansions.end(),

338 std::back_inserter(CommonArgExpansions));

339}

340

341

342

343

344

345

346

347

348

349

350

351static void

355

357

358 for (const auto &Range : Ranges) {

359 if (Range.isInvalid())

360 continue;

361

362 SourceLocation Begin = Range.getBegin(), End = Range.getEnd();

363 bool IsTokenRange = Range.isTokenRange();

364

365 FileID BeginFileID = SM->getFileID(Begin);

366 FileID EndFileID = SM->getFileID(End);

367

368

369

370

371 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;

372 while (Begin.isMacroID() && BeginFileID != EndFileID) {

373 BeginLocsMap[BeginFileID] = Begin;

374 Begin = SM->getImmediateExpansionRange(Begin).getBegin();

375 BeginFileID = SM->getFileID(Begin);

376 }

377

378

379 if (BeginFileID != EndFileID) {

380 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {

381 auto Exp = SM->getImmediateExpansionRange(End);

382 IsTokenRange = Exp.isTokenRange();

383 End = Exp.getEnd();

384 EndFileID = SM->getFileID(End);

385 }

386 if (End.isMacroID()) {

387 Begin = BeginLocsMap[EndFileID];

388 BeginFileID = EndFileID;

389 }

390 }

391

392

393

394

395

396 if (Begin.isInvalid() || End.isInvalid() || BeginFileID != EndFileID)

397 continue;

398

399

403 CommonArgExpansions, true, SM,

404 IsTokenRange);

406 CommonArgExpansions, false, SM,

407 IsTokenRange);

408 if (Begin.isInvalid() || End.isInvalid()) continue;

409

410

411 Begin = SM->getSpellingLoc(Begin);

412 End = SM->getSpellingLoc(End);

413

415 IsTokenRange));

416 }

417}

418

419void DiagnosticRenderer::emitCaret(FullSourceLoc Loc,

423 SmallVector<CharSourceRange, 4> SpellingRanges;

426}

427

428

429

430void DiagnosticRenderer::emitSingleMacroExpansion(

433

434

436

437

438 SmallVector<CharSourceRange, 4> SpellingRanges;

440

441 SmallString<100> MessageStorage;

442 llvm::raw_svector_ostream Message(MessageStorage);

445 if (MacroName.empty())

446 Message << "expanded from here";

447 else

448 Message << "expanded from macro '" << MacroName << "'";

449

451 SpellingRanges, {});

452}

453

454

455

456static bool

459 assert(Loc.isMacroID() && "Must be a macro expansion!");

460

463

464 unsigned ValidCount =

465 llvm::count_if(Ranges, [](const auto &R) { return R.isValid(); });

466 if (ValidCount > SpellingRanges.size())

467 return false;

468

470 for (const auto &R : Ranges) {

471

473 if (Begin == R.getEnd()) {

474 if (SM.isMacroArgExpansion(Begin))

475 return false;

476 continue;

477 }

478

479 while (Begin != R.getEnd()) {

481 if (SM.isMacroArgExpansion(Begin, &MacroLoc))

482 return false;

483 if (MacroLoc != Loc)

484 return false;

485

487 }

488 }

489

490 return true;

491}

492

493

494

495

496

497

498

499

500

501

502

503

504void DiagnosticRenderer::emitMacroExpansions(FullSourceLoc Loc,

508 assert(Loc.isValid() && "must have a valid source location here");

510 SourceLocation L = Loc;

511

512

513 SmallVector<SourceLocation, 8> LocationStack;

514 unsigned IgnoredEnd = 0;

516

517

518 if (SM.isMacroArgExpansion(L)) {

519 LocationStack.push_back(SM.getImmediateExpansionRange(L).getBegin());

520

522 IgnoredEnd = LocationStack.size();

523 } else

524 LocationStack.push_back(L);

525

526 L = SM.getImmediateMacroCallerLoc(L);

527

528

529

530

532 L = SM.getImmediateMacroCallerLoc(LocationStack.back());

533 assert(L.isValid() && "must have a valid source location here");

534 }

535

536 LocationStack.erase(LocationStack.begin(),

537 LocationStack.begin() + IgnoredEnd);

538

539 unsigned MacroDepth = LocationStack.size();

540 unsigned MacroLimit = DiagOpts.MacroBacktraceLimit;

541 if (MacroDepth <= MacroLimit || MacroLimit == 0) {

542 for (auto I = LocationStack.rbegin(), E = LocationStack.rend();

543 I != E; ++I)

544 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);

545 return;

546 }

547

548 unsigned MacroStartMessages = MacroLimit / 2;

549 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;

550

551 for (auto I = LocationStack.rbegin(),

552 E = LocationStack.rbegin() + MacroStartMessages;

553 I != E; ++I)

554 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);

555

556 SmallString<200> MessageStorage;

557 llvm::raw_svector_ostream Message(MessageStorage);

558 Message << "(skipping " << (MacroDepth - MacroLimit)

559 << " expansions in backtrace; use -fmacro-backtrace-limit=0 to "

560 "see all)";

561 emitBasicNote(Message.str());

562

563 for (auto I = LocationStack.rend() - MacroEndMessages,

564 E = LocationStack.rend();

565 I != E; ++I)

566 emitSingleMacroExpansion(FullSourceLoc(*I, SM), Level, Ranges);

567}

568

570

573

575 llvm::raw_svector_ostream Message(MessageStorage);

576 Message << "in file included from " << PLoc.getFilename() << ':'

577 << PLoc.getLine() << ":";

578 emitNote(Loc, Message.str());

579}

580

583 StringRef ModuleName) {

584

586 llvm::raw_svector_ostream Message(MessageStorage);

587 Message << "in module '" << ModuleName;

589 Message << "' imported from " << PLoc.getFilename() << ':'

591 Message << ":";

592 emitNote(Loc, Message.str());

593}

594

597 StringRef ModuleName) {

598

600 llvm::raw_svector_ostream Message(MessageStorage);

602 Message << "while building module '" << ModuleName << "' imported from "

604 else

605 Message << "while building module '" << ModuleName << "':";

606 emitNote(Loc, Message.str());

607}

Defines the Diagnostic-related interfaces.

static void getMacroArgExpansionFileIDs(SourceLocation Loc, SmallVectorImpl< FileID > &IDs, bool IsBegin, const SourceManager *SM)

Walk up the chain of macro expansions and collect the FileIDs identifying the expansions.

Definition DiagnosticRenderer.cpp:311

static SourceLocation retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID, FileID CaretFileID, const SmallVectorImpl< FileID > &CommonArgExpansions, bool IsBegin, const SourceManager *SM, bool &IsTokenRange)

A recursive function to trace all possible backtrace locations to match the CaretLocFileID.

Definition DiagnosticRenderer.cpp:257

static void computeCommonMacroArgExpansionFileIDs(SourceLocation Begin, SourceLocation End, const SourceManager *SM, SmallVectorImpl< FileID > &CommonArgExpansions)

Collect the expansions of the begin and end locations and compute the set intersection.

Definition DiagnosticRenderer.cpp:327

static void mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef< CharSourceRange > Ranges, SmallVectorImpl< CharSourceRange > &SpellingRanges)

Definition DiagnosticRenderer.cpp:352

static void mergeFixits(ArrayRef< FixItHint > FixItHints, const SourceManager &SM, const LangOptions &LangOpts, SmallVectorImpl< FixItHint > &MergedFixits)

Definition DiagnosticRenderer.cpp:57

static bool rangesInsideSameMacroArgExpansion(FullSourceLoc Loc, ArrayRef< CharSourceRange > Ranges)

A helper function to check if the current ranges are all inside the same macro argument expansion as ...

Definition DiagnosticRenderer.cpp:457

Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified.

static DiagnosticBuilder Diag(DiagnosticsEngine *Diags, const LangOptions &Features, FullSourceLoc TokLoc, const char *TokBegin, const char *TokRangeBegin, const char *TokRangeEnd, unsigned DiagID)

Produce a diagnostic highlighting some portion of a literal.

Defines the clang::SourceLocation class and associated facilities.

Defines the SourceManager interface.

Represents a character-granular source range.

bool isTokenRange() const

Return true if the end of this range specifies the start of the last token.

SourceLocation getEnd() const

SourceLocation getBegin() const

~DiagnosticNoteRenderer() override

virtual void emitNote(FullSourceLoc Loc, StringRef Message)=0

void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override

Definition DiagnosticRenderer.cpp:595

void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override

Definition DiagnosticRenderer.cpp:571

void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override

Definition DiagnosticRenderer.cpp:581

Options for controlling the compiler diagnostics engine.

virtual void endDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)

virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc)=0

virtual ~DiagnosticRenderer()

const LangOptions & LangOpts

void emitStoredDiagnostic(StoredDiagnostic &Diag)

Definition DiagnosticRenderer.cpp:140

SourceLocation LastLoc

The location of the previous diagnostic if known.

DiagnosticOptions & DiagOpts

DiagnosticsEngine::Level LastLevel

The level of the last diagnostic emitted.

virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName)=0

virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, DiagOrStoredDiag Info)=0

SourceLocation LastIncludeLoc

The location of the last include whose stack was printed if known.

virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName)=0

void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, ArrayRef< FixItHint > FixItHints, DiagOrStoredDiag D=(Diagnostic *) nullptr)

Emit a diagnostic.

Definition DiagnosticRenderer.cpp:85

virtual void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, SmallVectorImpl< CharSourceRange > &Ranges, ArrayRef< FixItHint > Hints)=0

DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions &DiagOpts)

Definition DiagnosticRenderer.cpp:31

virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)

Level

The level of the diagnostic, after it has been through mapping.

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)

Create a code modification hint that replaces the given source range with the given code string.

static FixItHint CreateInsertion(SourceLocation InsertionLoc, StringRef Code, bool BeforePreviousInsertions=false)

Create a code modification hint that inserts the given code string at a specific location.

A SourceLocation and its associated SourceManager.

FullSourceLoc getFileLoc() const

FullSourceLoc getSpellingLoc() const

std::pair< FullSourceLoc, StringRef > getModuleImportLoc() const

PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const

bool hasManager() const

Checks whether the SourceManager is present.

const SourceManager & getManager() const

Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...

static StringRef getImmediateMacroNameForDiagnostics(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)

Retrieve the name of the immediate macro expansion.

Represents an unpacked "presumed" location which can be presented to the user.

const char * getFilename() const

Return the presumed filename of this location.

unsigned getLine() const

Return the presumed line number of this location.

bool isInvalid() const

Return true if this object is invalid or uninitialized.

SourceLocation getIncludeLoc() const

Return the presumed include location of this location.

Encodes a location in the source.

bool isValid() const

Return true if this is a valid SourceLocation object.

SourceLocation getLocWithOffset(IntTy Offset) const

Return a source location with the specified offset from this SourceLocation.

This class handles loading and caching of source files into memory.

A trivial tuple used to represent a source range.

Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...

bool insertFromRange(SourceLocation loc, CharSourceRange range, bool afterToken=false, bool beforePreviousInsertions=false)

bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)

bool remove(CharSourceRange range)

bool replace(CharSourceRange range, StringRef text)

void applyRewrites(EditsReceiver &receiver, bool adjustRemovals=true)

bool commit(const Commit &commit)

The JSON file list parser is used to communicate input to InstallAPI.

if(T->getSizeExpr()) TRY_TO(TraverseStmt(const_cast< Expr * >(T -> getSizeExpr())))

llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag

ArrayRef< std::pair< std::string, FullSourceLoc > > ModuleBuildStack

The stack used when building modules on demand, which is used to provide a link between the source ma...