17#include "llvm/ADT/ArrayRef.h"
18#include "llvm/ADT/DenseMap.h"
19#include "llvm/ADT/SmallVector.h"
20#include "llvm/ADT/StringRef.h"
21#include "llvm/Support/raw_ostream.h"
35std::optional<CharSourceRange>
38 if (Range.isInvalid())
74 if (!FixItHints.empty()) {
76 FixItHints = MergedFixits;
79 for (
const auto &Hint : FixItHints)
80 if (Hint.RemoveRange.isValid())
81 MutableRanges.push_back(Hint.RemoveRange);
92 emitIncludeStack(Loc, PLoc, Level);
96 emitCaret(Loc, Level, MutableRanges, FixItHints);
101 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
117void DiagnosticRenderer::emitBasicNote(StringRef Message) {
135 FullSourceLoc IncludeLoc =
137 : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
149 emitIncludeStackRecursively(IncludeLoc);
152 emitImportStack(Loc);
158void DiagnosticRenderer::emitIncludeStackRecursively(
FullSourceLoc Loc) {
172 if (!Imported.second.empty()) {
174 emitImportStackRecursively(Imported.first, Imported.second);
179 emitIncludeStackRecursively(
194 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
199void DiagnosticRenderer::emitImportStackRecursively(
FullSourceLoc Loc,
200 StringRef ModuleName) {
201 if (ModuleName.empty()) {
209 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
217void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &SM) {
219 for (
const auto &I : Stack) {
221 I.second, I.second.getPresumedLoc(
DiagOpts.ShowPresumedLoc), I.first);
232 bool &IsTokenRange) {
233 assert(SM->
getFileID(Loc) == MacroFileID);
234 if (MacroFileID == CaretFileID)
244 if (llvm::binary_search(CommonArgExpansions, MacroFileID))
257 MacroFileID = SM->
getFileID(MacroLocation);
258 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.
isTokenRange();
261 CommonArgExpansions, IsBegin, SM, TokenRange);
263 IsTokenRange = TokenRange;
264 return MacroLocation;
275 MacroFileID = SM->
getFileID(MacroArgLocation);
277 CommonArgExpansions, IsBegin, SM, IsTokenRange);
291 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
305 llvm::sort(BeginArgExpansions);
306 llvm::sort(EndArgExpansions);
307 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
308 EndArgExpansions.begin(), EndArgExpansions.end(),
309 std::back_inserter(CommonArgExpansions));
329 for (
const auto &Range : Ranges) {
330 if (Range.isInvalid())
334 bool IsTokenRange = Range.isTokenRange();
342 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
343 while (Begin.
isMacroID() && BeginFileID != EndFileID) {
344 BeginLocsMap[BeginFileID] = Begin;
350 if (BeginFileID != EndFileID) {
351 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
353 IsTokenRange = Exp.isTokenRange();
357 if (End.isMacroID()) {
358 Begin = BeginLocsMap[EndFileID];
359 BeginFileID = EndFileID;
367 if (Begin.
isInvalid() || End.isInvalid() || BeginFileID != EndFileID)
374 CommonArgExpansions,
true, SM,
377 CommonArgExpansions,
false, SM,
379 if (Begin.
isInvalid() || End.isInvalid())
continue;
394 SmallVector<CharSourceRange, 4> SpellingRanges;
401void DiagnosticRenderer::emitSingleMacroExpansion(
409 SmallVector<CharSourceRange, 4> SpellingRanges;
412 SmallString<100> MessageStorage;
413 llvm::raw_svector_ostream
Message(MessageStorage);
416 if (MacroName.empty())
417 Message <<
"expanded from here";
419 Message <<
"expanded from macro '" << MacroName <<
"'";
430 assert(Loc.
isMacroID() &&
"Must be a macro expansion!");
435 unsigned ValidCount =
436 llvm::count_if(Ranges, [](
const auto &R) {
return R.isValid(); });
437 if (ValidCount > SpellingRanges.size())
441 for (
const auto &R : Ranges) {
444 if (Begin == R.getEnd()) {
450 while (Begin != R.getEnd()) {
475void DiagnosticRenderer::emitMacroExpansions(
FullSourceLoc Loc,
479 assert(Loc.
isValid() &&
"must have a valid source location here");
481 SourceLocation L = Loc;
484 SmallVector<SourceLocation, 8> LocationStack;
485 unsigned IgnoredEnd = 0;
493 IgnoredEnd = LocationStack.size();
495 LocationStack.push_back(L);
504 assert(L.
isValid() &&
"must have a valid source location here");
507 LocationStack.erase(LocationStack.begin(),
508 LocationStack.begin() + IgnoredEnd);
510 unsigned MacroDepth = LocationStack.size();
511 unsigned MacroLimit =
DiagOpts.MacroBacktraceLimit;
512 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
513 for (
auto I = LocationStack.rbegin(), E = LocationStack.rend();
515 emitSingleMacroExpansion(FullSourceLoc(*I, SM),
Level, Ranges);
519 unsigned MacroStartMessages = MacroLimit / 2;
520 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
522 for (
auto I = LocationStack.rbegin(),
523 E = LocationStack.rbegin() + MacroStartMessages;
525 emitSingleMacroExpansion(FullSourceLoc(*I, SM),
Level, Ranges);
527 SmallString<200> MessageStorage;
528 llvm::raw_svector_ostream
Message(MessageStorage);
529 Message <<
"(skipping " << (MacroDepth - MacroLimit)
530 <<
" expansions in backtrace; use -fmacro-backtrace-limit=0 to "
534 for (
auto I = LocationStack.rend() - MacroEndMessages,
535 E = LocationStack.rend();
537 emitSingleMacroExpansion(FullSourceLoc(*I, SM),
Level, Ranges);
546 llvm::raw_svector_ostream Message(MessageStorage);
547 Message <<
"in file included from " << PLoc.
getFilename() <<
':'
554 StringRef ModuleName) {
557 llvm::raw_svector_ostream Message(MessageStorage);
558 Message <<
"in module '" << ModuleName;
560 Message <<
"' imported from " << PLoc.
getFilename() <<
':'
568 StringRef ModuleName) {
571 llvm::raw_svector_ostream Message(MessageStorage);
573 Message <<
"while building module '" << ModuleName <<
"' imported from "
576 Message <<
"while building module '" << ModuleName <<
"':";
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.
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 void mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef< CharSourceRange > Ranges, SmallVectorImpl< CharSourceRange > &SpellingRanges)
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 ...
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 byte-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.
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
DiagnosticRenderer(const LangOptions &LangOpts, 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...
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.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
unsigned getFileOffset(SourceLocation SpellingLoc) const
Returns the offset from the start of the file that the specified SourceLocation represents.
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
ModuleBuildStack getModuleBuildStack() const
Retrieve the module build stack.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const
Gets the location of the immediate macro caller, one level up the stack toward the initial macro type...
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
CharSourceRange getExpansionRange(SourceLocation Loc) const
Given a SourceLocation object, return the range of tokens covered by the expansion in the ultimate fi...
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID.
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...
void mergeFixits(ArrayRef< FixItHint > FixItHints, const SourceManager &SM, const LangOptions &LangOpts, SmallVectorImpl< FixItHint > &MergedFixits)
Merges FixItHints into a normalized set of file edits.
Top level wrappers for InstallAPI frontend operations.
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...
std::optional< CharSourceRange > getExpansionRangeInFile(CharSourceRange Range, FileID FID, const SourceManager &SM)
Maps both endpoints of Range to their macro expansion, so that the range can be shown to a user.