18 #include "llvm/ADT/SmallSet.h"
19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/Support/ErrorHandling.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/raw_ostream.h"
24 using namespace clang;
45 assert(Loc.
isMacroID() &&
"Only reasonble to call this on macros");
64 StringRef ExpansionBuffer = SM.
getBufferData(ExpansionInfo.first);
65 return ExpansionBuffer.substr(ExpansionInfo.second, MacroTokenLength);
70 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
81 : MergedFixits(MergedFixits) { }
97 I = FixItHints.begin(),
E = FixItHints.end();
I !=
E; ++
I) {
117 if (Editor.
commit(commit)) {
118 FixitReceiver Rec(MergedFixits);
143 if (!FixItHints.empty()) {
145 FixItHints = MergedFixits;
149 E = FixItHints.end();
151 if (
I->RemoveRange.isValid())
152 MutableRanges.push_back(
I->RemoveRange);
157 Loc = SM->getFileLoc(Loc);
163 emitIncludeStack(Loc, PLoc, Level, *SM);
167 emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
172 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM);
191 void DiagnosticRenderer::emitBasicNote(StringRef Message) {
224 emitIncludeStackRecursively(IncludeLoc, SM);
226 emitModuleBuildStack(SM);
227 emitImportStack(Loc, SM);
233 void DiagnosticRenderer::emitIncludeStackRecursively(
SourceLocation Loc,
236 emitModuleBuildStack(SM);
248 if (!Imported.second.empty()) {
250 emitImportStackRecursively(Imported.first, Imported.second, SM);
265 emitModuleBuildStack(SM);
269 std::pair<SourceLocation, StringRef> NextImportLoc
271 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
276 void DiagnosticRenderer::emitImportStackRecursively(
SourceLocation Loc,
277 StringRef ModuleName,
279 if (ModuleName.empty()) {
286 std::pair<SourceLocation, StringRef> NextImportLoc
288 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
296 void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &SM) {
298 for (
unsigned I = 0, N = Stack.size();
I != N; ++
I) {
316 assert(SM->
getFileID(Loc) == MacroFileID);
317 if (MacroFileID == CaretFileID)
327 if (std::binary_search(CommonArgExpansions.begin(),
328 CommonArgExpansions.end(), MacroFileID))
339 MacroFileID = SM->
getFileID(MacroLocation);
342 CommonArgExpansions, IsBegin, SM);
344 return MacroLocation;
347 MacroFileID = SM->
getFileID(MacroArgLocation);
349 CommonArgExpansions, IsBegin, SM);
363 Loc = IsBegin ? ExpRange.first : ExpRange.second;
377 std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end());
378 std::sort(EndArgExpansions.begin(), EndArgExpansions.end());
379 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
380 EndArgExpansions.begin(), EndArgExpansions.end(),
381 std::back_inserter(CommonArgExpansions));
401 for (
auto I = Ranges.begin(),
E = Ranges.end();
I !=
E; ++
I) {
402 if (
I->isInvalid())
continue;
405 bool IsTokenRange =
I->isTokenRange();
413 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
414 while (Begin.
isMacroID() && BeginFileID != EndFileID) {
415 BeginLocsMap[BeginFileID] = Begin;
421 if (BeginFileID != EndFileID) {
422 while (
End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
426 if (
End.isMacroID()) {
427 Begin = BeginLocsMap[EndFileID];
428 BeginFileID = EndFileID;
436 CommonArgExpansions,
true, SM);
438 CommonArgExpansions,
false, SM);
462 void DiagnosticRenderer::emitSingleMacroExpansion(
476 llvm::raw_svector_ostream Message(MessageStorage);
478 if (MacroName.empty())
479 Message <<
"expanded from here";
481 Message <<
"expanded from macro '" << MacroName <<
"'";
484 SpellingRanges,
None, &
SM);
495 if (ArgumentLoc == MacroLoc)
return true;
507 while (BegLoc != EndLoc) {
521 assert(Loc.
isMacroID() &&
"Must be a macro expansion!");
527 unsigned ValidCount = 0;
528 for (
auto I : Ranges)
529 if (
I.isValid()) ValidCount++;
531 if (ValidCount > SpellingRanges.size())
542 for (
auto I = SpellingRanges.begin(),
E = SpellingRanges.end();
I !=
E; ++
I) {
566 assert(Loc.
isValid() &&
"must have a valid source location here");
570 unsigned IgnoredEnd = 0;
577 LocationStack.push_back(Loc);
580 IgnoredEnd = LocationStack.size();
589 assert(Loc.
isValid() &&
"must have a valid source location here");
592 LocationStack.erase(LocationStack.begin(),
593 LocationStack.begin() + IgnoredEnd);
595 unsigned MacroDepth = LocationStack.size();
596 unsigned MacroLimit =
DiagOpts->MacroBacktraceLimit;
597 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
598 for (
auto I = LocationStack.rbegin(),
E = LocationStack.rend();
600 emitSingleMacroExpansion(*
I, Level, Ranges, SM);
604 unsigned MacroStartMessages = MacroLimit / 2;
605 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
607 for (
auto I = LocationStack.rbegin(),
608 E = LocationStack.rbegin() + MacroStartMessages;
610 emitSingleMacroExpansion(*
I, Level, Ranges, SM);
613 llvm::raw_svector_ostream Message(MessageStorage);
614 Message <<
"(skipping " << (MacroDepth - MacroLimit)
615 <<
" expansions in backtrace; use -fmacro-backtrace-limit=0 to "
617 emitBasicNote(Message.str());
619 for (
auto I = LocationStack.rend() - MacroEndMessages,
620 E = LocationStack.rend();
622 emitSingleMacroExpansion(*
I, Level, Ranges, SM);
632 llvm::raw_svector_ostream Message(MessageStorage);
633 Message <<
"in file included from " << PLoc.
getFilename() <<
':'
640 StringRef ModuleName,
644 llvm::raw_svector_ostream Message(MessageStorage);
645 Message <<
"in module '" << ModuleName;
647 Message <<
"' imported from " << PLoc.
getFilename() <<
':'
656 StringRef ModuleName,
660 llvm::raw_svector_ostream Message(MessageStorage);
662 Message <<
"while building module '" << ModuleName <<
"' imported from "
665 Message <<
"while building module '" << ModuleName <<
"':";
bool isMacroArgExpansion(SourceLocation Loc, SourceLocation *StartLoc=nullptr) const
Tests whether the given source location represents a macro argument's expansion into the function-lik...
bool remove(CharSourceRange range)
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.
void emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, ArrayRef< FixItHint > FixItHints, const SourceManager *SM, DiagOrStoredDiag D=(Diagnostic *) nullptr)
Emit a diagnostic.
SourceLocation getBegin() const
Defines the clang::FileManager interface and associated types.
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
bool isInvalid() const
Return true if this object is invalid or uninitialized.
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.
Defines the SourceManager interface.
virtual void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, StringRef ModuleName, const SourceManager &SM)=0
StringRef getMessage() const
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
void emitStoredDiagnostic(StoredDiagnostic &Diag)
const SourceManager & getManager() const
const FullSourceLoc & getLocation() const
std::string CodeToInsert
The actual code to insert at the insertion location, as a string.
static SourceLocation retrieveMacroLocation(SourceLocation Loc, FileID MacroFileID, FileID CaretFileID, const SmallVectorImpl< FileID > &CommonArgExpansions, bool IsBegin, const SourceManager *SM)
A recursive function to trace all possible backtrace locations to match the CaretLocFileID.
bool insertFromRange(SourceLocation loc, CharSourceRange range, bool afterToken=false, bool beforePreviousInsertions=false)
const LangOptions & LangOpts
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 that expansi...
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.
void applyRewrites(EditsReceiver &receiver)
bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)
virtual ~DiagnosticRenderer()
StringRef getBufferData(FileID FID, bool *Invalid=nullptr) const
Return a StringRef to the source buffer data for the specified FileID.
virtual void emitDiagnosticMessage(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, const SourceManager *SM, DiagOrStoredDiag Info)=0
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
bool replace(CharSourceRange range, StringRef text)
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
SourceLocation getImmediateMacroCallerLoc(SourceLocation Loc) const
Gets the location of the immediate macro caller, one level up the stack toward the initial macro type...
void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, StringRef ModuleName, const SourceManager &SM) override
DiagnosticsEngine::Level LastLevel
The level of the last diagnostic emitted.
unsigned getLine() const
Return the presumed line number of this location.
void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM) override
detail::InMemoryDirectory::const_iterator I
SourceLocation getIncludeLoc() const
Return the presumed include location of this location.
const FileEntry * getFileEntryForID(FileID FID) const
Returns the FileEntry record for the provided FileID.
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
static void mapDiagnosticRanges(SourceLocation CaretLoc, ArrayRef< CharSourceRange > Ranges, SmallVectorImpl< CharSourceRange > &SpellingRanges, const SourceManager *SM)
std::vector< bool > & Stack
ModuleBuildStack getModuleBuildStack() const
Retrieve the module build stack.
Represents a character-granular source range.
SourceLocation getEnd() const
static unsigned MeasureTokenLength(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
MeasureTokenLength - Relex the token at the specified location and return its length in bytes in the ...
static bool checkLocForMacroArgExpansion(SourceLocation Loc, const SourceManager &SM, SourceLocation ArgumentLoc)
Check that the macro argument location of Loc starts with ArgumentLoc.
std::pair< SourceLocation, StringRef > getModuleImportLoc(SourceLocation Loc) const
static bool checkRangesForMacroArgExpansion(SourceLocation Loc, ArrayRef< CharSourceRange > Ranges, const SourceManager &SM)
A helper function to check if the current ranges are all inside the same macro argument expansion as ...
bool BeforePreviousInsertions
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
Represents an unpacked "presumed" location which can be presented to the user.
static StringRef getImmediateMacroName(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
CharSourceRange InsertFromRange
Code in the specific range that should be inserted in the insertion location.
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
ArrayRef< FixItHint > getFixIts() const
virtual void emitCodeContext(SourceLocation Loc, DiagnosticsEngine::Level Level, SmallVectorImpl< CharSourceRange > &Ranges, ArrayRef< FixItHint > Hints, const SourceManager &SM)=0
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
const char * getFilename() const
Return the presumed filename of this location.
Encodes a location in the source.
bool isValid() const
Return true if this is a valid SourceLocation object.
Options for controlling the compiler diagnostics engine.
virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
virtual void emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM)=0
DiagnosticRenderer(const LangOptions &LangOpts, DiagnosticOptions *DiagOpts)
~DiagnosticNoteRenderer() override
An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...
SourceLocation LastLoc
The location of the previous diagnostic if known.
SourceLocation LastIncludeLoc
The location of the last include whose stack was printed if known.
std::pair< SourceLocation, SourceLocation > getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
virtual void endDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
detail::InMemoryDirectory::const_iterator E
virtual void emitNote(SourceLocation Loc, StringRef Message, const SourceManager *SM)=0
static void mergeFixits(ArrayRef< FixItHint > FixItHints, const SourceManager &SM, const LangOptions &LangOpts, SmallVectorImpl< FixItHint > &MergedFixits)
bool commit(const Commit &commit)
void emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, StringRef ModuleName, const SourceManager &SM) override
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.
ArrayRef< CharSourceRange > getRanges() const
Level
The level of the diagnostic, after it has been through mapping.
static FixItHint CreateReplacement(CharSourceRange RemoveRange, StringRef Code)
Create a code modification hint that replaces the given source range with the given code string...
DiagnosticsEngine::Level getLevel() const
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
virtual void emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, StringRef ModuleName, const SourceManager &SM)=0
A trivial tuple used to represent a source range.
std::pair< FileID, unsigned > getDecomposedLoc(SourceLocation Loc) const
Decompose the specified location into a raw FileID + Offset pair.
This class handles loading and caching of source files into memory.
PresumedLoc getPresumedLoc(SourceLocation Loc, bool UseLineDirectives=true) const
Returns the "presumed" location of a SourceLocation specifies.