19#include "llvm/ADT/ArrayRef.h"
20#include "llvm/ADT/DenseMap.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"
34 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
45 : MergedFixits(MergedFixits) {}
62 for (
const auto &Hint : FixItHints)
63 if (Hint.CodeToInsert.empty()) {
64 if (Hint.InsertFromRange.isValid())
66 Hint.InsertFromRange,
false,
67 Hint.BeforePreviousInsertions);
69 commit.
remove(Hint.RemoveRange);
71 if (Hint.RemoveRange.isTokenRange() ||
72 Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
73 commit.
replace(Hint.RemoveRange, Hint.CodeToInsert);
75 commit.
insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
76 false, Hint.BeforePreviousInsertions);
80 if (Editor.
commit(commit)) {
81 FixitReceiver Rec(MergedFixits);
104 if (!FixItHints.empty()) {
106 FixItHints = MergedFixits;
109 for (
const auto &Hint : FixItHints)
110 if (Hint.RemoveRange.isValid())
111 MutableRanges.push_back(Hint.RemoveRange);
122 emitIncludeStack(
Loc, PLoc, Level);
126 emitCaret(
Loc, Level, MutableRanges, FixItHints);
131 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
147void DiagnosticRenderer::emitBasicNote(StringRef Message) {
179 emitIncludeStackRecursively(IncludeLoc);
181 emitModuleBuildStack(
Loc.getManager());
182 emitImportStack(
Loc);
190 emitModuleBuildStack(
Loc.getManager());
201 std::pair<FullSourceLoc, StringRef> Imported =
Loc.getModuleImportLoc();
202 if (!Imported.second.empty()) {
204 emitImportStackRecursively(Imported.first, Imported.second);
209 emitIncludeStackRecursively(
219 emitModuleBuildStack(
Loc.getManager());
223 std::pair<FullSourceLoc, StringRef> NextImportLoc =
Loc.getModuleImportLoc();
224 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
230 StringRef ModuleName) {
231 if (ModuleName.empty()) {
238 std::pair<FullSourceLoc, StringRef> NextImportLoc =
Loc.getModuleImportLoc();
239 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
247void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &
SM) {
249 for (
const auto &I : Stack) {
263 bool &IsTokenRange) {
264 assert(
SM->getFileID(
Loc) == MacroFileID);
265 if (MacroFileID == CaretFileID)
272 if (
SM->isMacroArgExpansion(
Loc)) {
275 if (std::binary_search(CommonArgExpansions.begin(),
276 CommonArgExpansions.end(), MacroFileID))
279 MacroArgRange =
SM->getImmediateExpansionRange(
Loc);
281 MacroRange =
SM->getImmediateExpansionRange(
Loc);
289 MacroFileID =
SM->getFileID(MacroLocation);
290 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.
isTokenRange();
293 CommonArgExpansions, IsBegin,
SM, TokenRange);
295 IsTokenRange = TokenRange;
296 return MacroLocation;
307 MacroFileID =
SM->getFileID(MacroArgLocation);
309 CommonArgExpansions, IsBegin,
SM, IsTokenRange);
318 if (
SM->isMacroArgExpansion(
Loc)) {
319 IDs.push_back(
SM->getFileID(
Loc));
320 Loc =
SM->getImmediateSpellingLoc(
Loc);
322 auto ExpRange =
SM->getImmediateExpansionRange(
Loc);
323 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
337 llvm::sort(BeginArgExpansions);
338 llvm::sort(EndArgExpansions);
339 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
340 EndArgExpansions.begin(), EndArgExpansions.end(),
341 std::back_inserter(CommonArgExpansions));
361 for (
const auto &
Range : Ranges) {
366 bool IsTokenRange =
Range.isTokenRange();
369 FileID EndFileID =
SM->getFileID(End);
374 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
376 BeginLocsMap[BeginFileID] =
Begin;
377 Begin =
SM->getImmediateExpansionRange(
Begin).getBegin();
378 BeginFileID =
SM->getFileID(
Begin);
382 if (BeginFileID != EndFileID) {
383 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
384 auto Exp =
SM->getImmediateExpansionRange(End);
385 IsTokenRange = Exp.isTokenRange();
387 EndFileID =
SM->getFileID(End);
389 if (End.isMacroID()) {
390 Begin = BeginLocsMap[EndFileID];
391 BeginFileID = EndFileID;
399 if (
Begin.
isInvalid() || End.isInvalid() || BeginFileID != EndFileID)
406 CommonArgExpansions,
true,
SM,
409 CommonArgExpansions,
false,
SM,
415 End =
SM->getSpellingLoc(End);
433void DiagnosticRenderer::emitSingleMacroExpansion(
445 llvm::raw_svector_ostream Message(MessageStorage);
448 if (MacroName.empty())
449 Message <<
"expanded from here";
451 Message <<
"expanded from macro '" << MacroName <<
"'";
454 SpellingRanges, std::nullopt);
464 if (
SM.isMacroArgExpansion(
Loc, &MacroLoc)) {
465 if (ArgumentLoc == MacroLoc)
return true;
477 while (BegLoc != EndLoc) {
490 assert(
Loc.
isMacroID() &&
"Must be a macro expansion!");
496 unsigned ValidCount =
497 llvm::count_if(Ranges, [](
const auto &R) {
return R.isValid(); });
499 if (ValidCount > SpellingRanges.size())
507 if (!
Loc.isMacroArgExpansion(&ArgumentLoc))
510 for (
const auto &
Range : SpellingRanges)
532 assert(
Loc.
isValid() &&
"must have a valid source location here");
538 unsigned IgnoredEnd = 0;
542 if (
SM.isMacroArgExpansion(L))
543 LocationStack.push_back(
SM.getImmediateExpansionRange(L).getBegin());
545 LocationStack.push_back(L);
548 IgnoredEnd = LocationStack.size();
550 L =
SM.getImmediateMacroCallerLoc(L);
556 L =
SM.getImmediateMacroCallerLoc(LocationStack.back());
557 assert(L.
isValid() &&
"must have a valid source location here");
560 LocationStack.erase(LocationStack.begin(),
561 LocationStack.begin() + IgnoredEnd);
563 unsigned MacroDepth = LocationStack.size();
564 unsigned MacroLimit =
DiagOpts->MacroBacktraceLimit;
565 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
566 for (
auto I = LocationStack.rbegin(),
E = LocationStack.rend();
572 unsigned MacroStartMessages = MacroLimit / 2;
573 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
575 for (
auto I = LocationStack.rbegin(),
576 E = LocationStack.rbegin() + MacroStartMessages;
581 llvm::raw_svector_ostream Message(MessageStorage);
582 Message <<
"(skipping " << (MacroDepth - MacroLimit)
583 <<
" expansions in backtrace; use -fmacro-backtrace-limit=0 to "
585 emitBasicNote(Message.str());
587 for (
auto I = LocationStack.rend() - MacroEndMessages,
588 E = LocationStack.rend();
599 llvm::raw_svector_ostream Message(MessageStorage);
600 Message <<
"in file included from " << PLoc.
getFilename() <<
':'
607 StringRef ModuleName) {
610 llvm::raw_svector_ostream Message(MessageStorage);
611 Message <<
"in module '" << ModuleName;
613 Message <<
"' imported from " << PLoc.
getFilename() <<
':'
621 StringRef ModuleName) {
624 llvm::raw_svector_ostream Message(MessageStorage);
626 Message <<
"while building module '" << ModuleName <<
"' imported from "
629 Message <<
"while building module '" << ModuleName <<
"':";
Defines the Diagnostic-related interfaces.
static bool checkLocForMacroArgExpansion(SourceLocation Loc, const SourceManager &SM, SourceLocation ArgumentLoc)
Check that the macro argument location of Loc starts with ArgumentLoc.
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.
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.
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.
static bool checkRangeForMacroArgExpansion(CharSourceRange Range, const SourceManager &SM, SourceLocation ArgumentLoc)
Check if all the locations in the range have the same macro argument expansion, and that the expansio...
static bool checkRangesForMacroArgExpansion(FullSourceLoc Loc, ArrayRef< CharSourceRange > Ranges)
A helper function to check if the current ranges are all inside the same macro argument expansion as ...
static void mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef< CharSourceRange > Ranges, SmallVectorImpl< CharSourceRange > &SpellingRanges)
static void mergeFixits(ArrayRef< FixItHint > FixItHints, const SourceManager &SM, const LangOptions &LangOpts, SmallVectorImpl< FixItHint > &MergedFixits)
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
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
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)
SourceLocation LastLoc
The location of the previous diagnostic if known.
DiagnosticRenderer(const LangOptions &LangOpts, 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.
virtual void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, SmallVectorImpl< CharSourceRange > &Ranges, ArrayRef< FixItHint > Hints)=0
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
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.
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.
SourceLocation getEnd() const
SourceLocation getBegin() const
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.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag