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;
28 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
39 : MergedFixits(MergedFixits) { }
55 I = FixItHints.begin(),
E = FixItHints.end();
I !=
E; ++
I) {
75 if (Editor.
commit(commit)) {
76 FixitReceiver Rec(MergedFixits);
101 if (!FixItHints.empty()) {
103 FixItHints = MergedFixits;
107 E = FixItHints.end();
109 if (
I->RemoveRange.isValid())
110 MutableRanges.push_back(
I->RemoveRange);
115 Loc = SM->getFileLoc(Loc);
121 emitIncludeStack(Loc, PLoc, Level, *SM);
125 emitCaret(Loc, Level, MutableRanges, FixItHints, *SM);
130 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints, *SM);
149 void DiagnosticRenderer::emitBasicNote(StringRef Message) {
183 emitIncludeStackRecursively(IncludeLoc, SM);
185 emitModuleBuildStack(SM);
186 emitImportStack(Loc, SM);
192 void DiagnosticRenderer::emitIncludeStackRecursively(
SourceLocation Loc,
195 emitModuleBuildStack(SM);
207 if (!Imported.second.empty()) {
209 emitImportStackRecursively(Imported.first, Imported.second, SM);
224 emitModuleBuildStack(SM);
228 std::pair<SourceLocation, StringRef> NextImportLoc
230 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
235 void DiagnosticRenderer::emitImportStackRecursively(
SourceLocation Loc,
236 StringRef ModuleName,
238 if (ModuleName.empty()) {
245 std::pair<SourceLocation, StringRef> NextImportLoc
247 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second, SM);
255 void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &SM) {
257 for (
unsigned I = 0, N = Stack.size();
I != N; ++
I) {
275 assert(SM->
getFileID(Loc) == MacroFileID);
276 if (MacroFileID == CaretFileID)
286 if (std::binary_search(CommonArgExpansions.begin(),
287 CommonArgExpansions.end(), MacroFileID))
298 MacroFileID = SM->
getFileID(MacroLocation);
301 CommonArgExpansions, IsBegin, SM);
303 return MacroLocation;
306 MacroFileID = SM->
getFileID(MacroArgLocation);
308 CommonArgExpansions, IsBegin, SM);
322 Loc = IsBegin ? ExpRange.first : ExpRange.second;
336 std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end());
337 std::sort(EndArgExpansions.begin(), EndArgExpansions.end());
338 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
339 EndArgExpansions.begin(), EndArgExpansions.end(),
340 std::back_inserter(CommonArgExpansions));
360 for (
auto I = Ranges.begin(),
E = Ranges.end();
I !=
E; ++
I) {
361 if (
I->isInvalid())
continue;
364 bool IsTokenRange =
I->isTokenRange();
372 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
373 while (Begin.
isMacroID() && BeginFileID != EndFileID) {
374 BeginLocsMap[BeginFileID] = Begin;
380 if (BeginFileID != EndFileID) {
381 while (
End.isMacroID() && !BeginLocsMap.count(EndFileID)) {
385 if (
End.isMacroID()) {
386 Begin = BeginLocsMap[EndFileID];
387 BeginFileID = EndFileID;
395 CommonArgExpansions,
true, SM);
397 CommonArgExpansions,
false, SM);
421 void DiagnosticRenderer::emitSingleMacroExpansion(
435 llvm::raw_svector_ostream Message(MessageStorage);
436 StringRef MacroName =
438 if (MacroName.empty())
439 Message <<
"expanded from here";
441 Message <<
"expanded from macro '" << MacroName <<
"'";
444 SpellingRanges,
None, &
SM);
455 if (ArgumentLoc == MacroLoc)
return true;
467 while (BegLoc != EndLoc) {
481 assert(Loc.
isMacroID() &&
"Must be a macro expansion!");
487 unsigned ValidCount = 0;
488 for (
auto I : Ranges)
489 if (
I.isValid()) ValidCount++;
491 if (ValidCount > SpellingRanges.size())
502 for (
auto I = SpellingRanges.begin(),
E = SpellingRanges.end();
I !=
E; ++
I) {
526 assert(Loc.
isValid() &&
"must have a valid source location here");
530 unsigned IgnoredEnd = 0;
537 LocationStack.push_back(Loc);
540 IgnoredEnd = LocationStack.size();
549 assert(Loc.
isValid() &&
"must have a valid source location here");
552 LocationStack.erase(LocationStack.begin(),
553 LocationStack.begin() + IgnoredEnd);
555 unsigned MacroDepth = LocationStack.size();
556 unsigned MacroLimit =
DiagOpts->MacroBacktraceLimit;
557 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
558 for (
auto I = LocationStack.rbegin(),
E = LocationStack.rend();
560 emitSingleMacroExpansion(*
I, Level, Ranges, SM);
564 unsigned MacroStartMessages = MacroLimit / 2;
565 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
567 for (
auto I = LocationStack.rbegin(),
568 E = LocationStack.rbegin() + MacroStartMessages;
570 emitSingleMacroExpansion(*
I, Level, Ranges, SM);
573 llvm::raw_svector_ostream Message(MessageStorage);
574 Message <<
"(skipping " << (MacroDepth - MacroLimit)
575 <<
" expansions in backtrace; use -fmacro-backtrace-limit=0 to "
577 emitBasicNote(Message.str());
579 for (
auto I = LocationStack.rend() - MacroEndMessages,
580 E = LocationStack.rend();
582 emitSingleMacroExpansion(*
I, Level, Ranges, SM);
592 llvm::raw_svector_ostream Message(MessageStorage);
593 Message <<
"in file included from " << PLoc.
getFilename() <<
':'
600 StringRef ModuleName,
604 llvm::raw_svector_ostream Message(MessageStorage);
605 Message <<
"in module '" << ModuleName;
607 Message <<
"' imported from " << PLoc.
getFilename() <<
':'
616 StringRef ModuleName,
620 llvm::raw_svector_ostream Message(MessageStorage);
622 Message <<
"while building module '" << ModuleName <<
"' imported from "
625 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()
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.
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 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.
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)
static StringRef getImmediateMacroNameForDiagnostics(SourceLocation Loc, const SourceManager &SM, const LangOptions &LangOpts)
Retrieve the name of the immediate macro expansion.
~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.
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.