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"
44 : MergedFixits(MergedFixits) {}
50 void replace(CharSourceRange range, StringRef text)
override {
61 for (
const auto &Hint : FixItHints)
62 if (Hint.CodeToInsert.empty()) {
63 if (Hint.InsertFromRange.isValid())
65 Hint.InsertFromRange,
false,
66 Hint.BeforePreviousInsertions);
68 commit.
remove(Hint.RemoveRange);
70 if (Hint.RemoveRange.isTokenRange() ||
71 Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
72 commit.
replace(Hint.RemoveRange, Hint.CodeToInsert);
74 commit.
insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
75 false, Hint.BeforePreviousInsertions);
79 if (Editor.
commit(commit)) {
80 FixitReceiver Rec(MergedFixits);
103 if (!FixItHints.empty()) {
105 FixItHints = MergedFixits;
108 for (
const auto &Hint : FixItHints)
109 if (Hint.RemoveRange.isValid())
110 MutableRanges.push_back(Hint.RemoveRange);
121 emitIncludeStack(Loc, PLoc, Level);
125 emitCaret(Loc, Level, MutableRanges, FixItHints);
130 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
146void DiagnosticRenderer::emitBasicNote(StringRef Message) {
164 FullSourceLoc IncludeLoc =
166 : FullSourceLoc(PLoc.getIncludeLoc(), Loc.getManager());
178 emitIncludeStackRecursively(IncludeLoc);
181 emitImportStack(Loc);
187void DiagnosticRenderer::emitIncludeStackRecursively(
FullSourceLoc Loc) {
201 if (!Imported.second.empty()) {
203 emitImportStackRecursively(Imported.first, Imported.second);
208 emitIncludeStackRecursively(
223 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
228void DiagnosticRenderer::emitImportStackRecursively(
FullSourceLoc Loc,
229 StringRef ModuleName) {
230 if (ModuleName.empty()) {
238 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
246void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &
SM) {
248 for (
const auto &I : Stack) {
250 I.second, I.second.getPresumedLoc(
DiagOpts.ShowPresumedLoc), I.first);
261 bool &IsTokenRange) {
262 assert(
SM->getFileID(Loc) == MacroFileID);
263 if (MacroFileID == CaretFileID)
270 if (
SM->isMacroArgExpansion(Loc)) {
273 if (llvm::binary_search(CommonArgExpansions, MacroFileID))
276 MacroArgRange =
SM->getImmediateExpansionRange(Loc);
278 MacroRange =
SM->getImmediateExpansionRange(Loc);
286 MacroFileID =
SM->getFileID(MacroLocation);
287 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.
isTokenRange();
290 CommonArgExpansions, IsBegin,
SM, TokenRange);
292 IsTokenRange = TokenRange;
293 return MacroLocation;
304 MacroFileID =
SM->getFileID(MacroArgLocation);
306 CommonArgExpansions, IsBegin,
SM, IsTokenRange);
315 if (
SM->isMacroArgExpansion(Loc)) {
316 IDs.push_back(
SM->getFileID(Loc));
317 Loc =
SM->getImmediateSpellingLoc(Loc);
319 auto ExpRange =
SM->getImmediateExpansionRange(Loc);
320 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
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));
358 for (
const auto &Range : Ranges) {
359 if (Range.isInvalid())
363 bool IsTokenRange = Range.isTokenRange();
365 FileID BeginFileID =
SM->getFileID(Begin);
366 FileID EndFileID =
SM->getFileID(End);
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);
379 if (BeginFileID != EndFileID) {
380 while (End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
381 auto Exp =
SM->getImmediateExpansionRange(End);
382 IsTokenRange = Exp.isTokenRange();
384 EndFileID =
SM->getFileID(End);
386 if (End.isMacroID()) {
387 Begin = BeginLocsMap[EndFileID];
388 BeginFileID = EndFileID;
396 if (Begin.
isInvalid() || End.isInvalid() || BeginFileID != EndFileID)
403 CommonArgExpansions,
true,
SM,
406 CommonArgExpansions,
false,
SM,
408 if (Begin.
isInvalid() || End.isInvalid())
continue;
411 Begin =
SM->getSpellingLoc(Begin);
412 End =
SM->getSpellingLoc(End);
423 SmallVector<CharSourceRange, 4> SpellingRanges;
430void DiagnosticRenderer::emitSingleMacroExpansion(
438 SmallVector<CharSourceRange, 4> SpellingRanges;
441 SmallString<100> MessageStorage;
442 llvm::raw_svector_ostream
Message(MessageStorage);
445 if (MacroName.empty())
446 Message <<
"expanded from here";
448 Message <<
"expanded from macro '" << MacroName <<
"'";
459 assert(Loc.
isMacroID() &&
"Must be a macro expansion!");
464 unsigned ValidCount =
465 llvm::count_if(Ranges, [](
const auto &R) {
return R.isValid(); });
466 if (ValidCount > SpellingRanges.size())
470 for (
const auto &R : Ranges) {
473 if (Begin == R.getEnd()) {
474 if (!
SM.isMacroArgExpansion(Begin))
479 while (Begin != R.getEnd()) {
481 if (!
SM.isMacroArgExpansion(Begin, &MacroLoc))
504void DiagnosticRenderer::emitMacroExpansions(
FullSourceLoc Loc,
508 assert(Loc.
isValid() &&
"must have a valid source location here");
510 SourceLocation L = Loc;
513 SmallVector<SourceLocation, 8> LocationStack;
514 unsigned IgnoredEnd = 0;
518 if (
SM.isMacroArgExpansion(L)) {
519 LocationStack.push_back(
SM.getImmediateExpansionRange(L).getBegin());
522 IgnoredEnd = LocationStack.size();
524 LocationStack.push_back(L);
526 L =
SM.getImmediateMacroCallerLoc(L);
532 L =
SM.getImmediateMacroCallerLoc(LocationStack.back());
533 assert(L.
isValid() &&
"must have a valid source location here");
536 LocationStack.erase(LocationStack.begin(),
537 LocationStack.begin() + IgnoredEnd);
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();
544 emitSingleMacroExpansion(FullSourceLoc(*I,
SM), Level, Ranges);
548 unsigned MacroStartMessages = MacroLimit / 2;
549 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
551 for (
auto I = LocationStack.rbegin(),
552 E = LocationStack.rbegin() + MacroStartMessages;
554 emitSingleMacroExpansion(FullSourceLoc(*I,
SM), Level, Ranges);
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 "
563 for (
auto I = LocationStack.rend() - MacroEndMessages,
564 E = LocationStack.rend();
566 emitSingleMacroExpansion(FullSourceLoc(*I,
SM), Level, Ranges);
575 llvm::raw_svector_ostream Message(MessageStorage);
576 Message <<
"in file included from " << PLoc.
getFilename() <<
':'
583 StringRef ModuleName) {
586 llvm::raw_svector_ostream Message(MessageStorage);
587 Message <<
"in module '" << ModuleName;
589 Message <<
"' imported from " << PLoc.
getFilename() <<
':'
597 StringRef ModuleName) {
600 llvm::raw_svector_ostream Message(MessageStorage);
602 Message <<
"while building module '" << ModuleName <<
"' imported from "
605 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 void mergeFixits(ArrayRef< FixItHint > FixItHints, const SourceManager &SM, const LangOptions &LangOpts, SmallVectorImpl< FixItHint > &MergedFixits)
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 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.
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...
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...