17 #include "llvm/ADT/SmallSet.h" 18 #include "llvm/ADT/SmallString.h" 19 #include "llvm/Support/ErrorHandling.h" 20 #include "llvm/Support/raw_ostream.h" 22 using namespace clang;
26 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
37 : MergedFixits(MergedFixits) { }
53 I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) {
73 if (Editor.
commit(commit)) {
74 FixitReceiver Rec(MergedFixits);
98 if (!FixItHints.empty()) {
100 FixItHints = MergedFixits;
104 E = FixItHints.end();
106 if (I->RemoveRange.isValid())
107 MutableRanges.push_back(I->RemoveRange);
118 emitIncludeStack(Loc, PLoc, Level);
122 emitCaret(Loc, Level, MutableRanges, FixItHints);
127 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
144 void DiagnosticRenderer::emitBasicNote(StringRef Message) {
176 emitIncludeStackRecursively(IncludeLoc);
179 emitImportStack(Loc);
185 void DiagnosticRenderer::emitIncludeStackRecursively(
FullSourceLoc Loc) {
199 if (!Imported.second.empty()) {
201 emitImportStackRecursively(Imported.first, Imported.second);
206 emitIncludeStackRecursively(
214 void DiagnosticRenderer::emitImportStack(
FullSourceLoc Loc) {
221 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
226 void DiagnosticRenderer::emitImportStackRecursively(
FullSourceLoc Loc,
227 StringRef ModuleName) {
228 if (ModuleName.empty()) {
236 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
244 void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &
SM) {
246 for (
unsigned I = 0, N = Stack.size(); I != N; ++I) {
260 assert(SM->
getFileID(Loc) == MacroFileID);
261 if (MacroFileID == CaretFileID)
271 if (std::binary_search(CommonArgExpansions.begin(),
272 CommonArgExpansions.end(), MacroFileID))
283 MacroFileID = SM->
getFileID(MacroLocation);
286 CommonArgExpansions, IsBegin, SM);
288 return MacroLocation;
291 MacroFileID = SM->
getFileID(MacroArgLocation);
293 CommonArgExpansions, IsBegin, SM);
307 Loc = IsBegin ? ExpRange.first : ExpRange.second;
321 std::sort(BeginArgExpansions.begin(), BeginArgExpansions.end());
322 std::sort(EndArgExpansions.begin(), EndArgExpansions.end());
323 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
324 EndArgExpansions.begin(), EndArgExpansions.end(),
325 std::back_inserter(CommonArgExpansions));
345 for (
auto I = Ranges.begin(), E = Ranges.end(); I != E; ++I) {
346 if (I->isInvalid())
continue;
349 bool IsTokenRange = I->isTokenRange();
357 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
358 while (Begin.
isMacroID() && BeginFileID != EndFileID) {
359 BeginLocsMap[BeginFileID] =
Begin;
365 if (BeginFileID != EndFileID) {
366 while (
End.
isMacroID() && !BeginLocsMap.count(EndFileID)) {
371 Begin = BeginLocsMap[EndFileID];
372 BeginFileID = EndFileID;
380 CommonArgExpansions,
true, SM);
382 CommonArgExpansions,
false, SM);
405 void DiagnosticRenderer::emitSingleMacroExpansion(
417 llvm::raw_svector_ostream Message(MessageStorage);
420 if (MacroName.empty())
421 Message <<
"expanded from here";
423 Message <<
"expanded from macro '" << MacroName <<
"'";
426 SpellingRanges,
None);
437 if (ArgumentLoc == MacroLoc)
return true;
449 while (BegLoc != EndLoc) {
462 assert(Loc.
isMacroID() &&
"Must be a macro expansion!");
468 unsigned ValidCount = 0;
469 for (
auto I : Ranges)
470 if (I.isValid()) ValidCount++;
472 if (ValidCount > SpellingRanges.size())
483 for (
auto I = SpellingRanges.begin(), E = SpellingRanges.end(); I != E; ++I) {
502 void DiagnosticRenderer::emitMacroExpansions(
FullSourceLoc Loc,
506 assert(Loc.
isValid() &&
"must have a valid source location here");
510 unsigned IgnoredEnd = 0;
517 LocationStack.push_back(Loc);
520 IgnoredEnd = LocationStack.size();
529 assert(Loc.
isValid() &&
"must have a valid source location here");
532 LocationStack.erase(LocationStack.begin(),
533 LocationStack.begin() + IgnoredEnd);
535 unsigned MacroDepth = LocationStack.size();
536 unsigned MacroLimit =
DiagOpts->MacroBacktraceLimit;
537 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
538 for (
auto I = LocationStack.rbegin(), E = LocationStack.rend();
540 emitSingleMacroExpansion(*I,
Level, Ranges);
544 unsigned MacroStartMessages = MacroLimit / 2;
545 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
547 for (
auto I = LocationStack.rbegin(),
548 E = LocationStack.rbegin() + MacroStartMessages;
550 emitSingleMacroExpansion(*I,
Level, Ranges);
553 llvm::raw_svector_ostream Message(MessageStorage);
554 Message <<
"(skipping " << (MacroDepth - MacroLimit)
555 <<
" expansions in backtrace; use -fmacro-backtrace-limit=0 to " 557 emitBasicNote(Message.str());
559 for (
auto I = LocationStack.rend() - MacroEndMessages,
560 E = LocationStack.rend();
562 emitSingleMacroExpansion(*I,
Level, Ranges);
571 llvm::raw_svector_ostream Message(MessageStorage);
572 Message <<
"in file included from " << PLoc.
getFilename() <<
':' 574 emitNote(Loc, Message.str());
579 StringRef ModuleName) {
582 llvm::raw_svector_ostream Message(MessageStorage);
583 Message <<
"in module '" << ModuleName;
585 Message <<
"' imported from " << PLoc.
getFilename() <<
':' 588 emitNote(Loc, Message.str());
593 StringRef ModuleName) {
596 llvm::raw_svector_ostream Message(MessageStorage);
598 Message <<
"while building module '" << ModuleName <<
"' imported from " 601 Message <<
"while building module '" << ModuleName <<
"':";
602 emitNote(Loc, Message.str());
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.
SourceLocation getLocWithOffset(int Offset) const
Return a source location with the specified offset from this SourceLocation.
void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
virtual void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level, SmallVectorImpl< CharSourceRange > &Ranges, ArrayRef< FixItHint > Hints)=0
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.
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
void emitStoredDiagnostic(StoredDiagnostic &Diag)
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.
virtual void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName)=0
void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc) override
FullSourceLoc getImmediateMacroCallerLoc() const
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 ...
bool insert(SourceLocation loc, StringRef text, bool afterToken=false, bool beforePreviousInsertions=false)
virtual ~DiagnosticRenderer()
SourceLocation getBegin() const
FullSourceLoc getFileLoc() const
Keeps track of the various options that can be enabled, which controls the dialect of C or C++ that i...
virtual void emitImportLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName)=0
bool replace(CharSourceRange range, StringRef text)
ModuleBuildStack getModuleBuildStack() const
Retrieve the module build stack.
void emitDiagnostic(FullSourceLoc Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, ArrayRef< FixItHint > FixItHints, DiagOrStoredDiag D=(Diagnostic *) nullptr)
Emit a diagnostic.
DiagnosticsEngine::Level LastLevel
The level of the last diagnostic emitted.
ArrayRef< CharSourceRange > getRanges() const
PresumedLoc getPresumedLoc(bool UseLineDirectives=true) const
SourceLocation getSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
StringRef getMessage() const
SourceLocation getImmediateSpellingLoc(SourceLocation Loc) const
Given a SourceLocation object, return the spelling location referenced by the ID. ...
bool isMacroArgExpansion(FullSourceLoc *StartLoc=nullptr) const
Represents a character-granular source range.
DiagnosticsEngine::Level getLevel() const
bool isInvalid() const
Return true if this object is invalid or uninitialized.
ArrayRef< FixItHint > getFixIts() const
unsigned getLine() const
Return the presumed line number of this location.
static bool checkLocForMacroArgExpansion(SourceLocation Loc, const SourceManager &SM, SourceLocation ArgumentLoc)
Check that the macro argument location of Loc starts with ArgumentLoc.
const SourceManager & getManager() const
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.
virtual void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef< CharSourceRange > Ranges, DiagOrStoredDiag Info)=0
const char * getFilename() const
Return the presumed filename of this location.
CharSourceRange RemoveRange
Code that should be replaced to correct the error.
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
Encodes a location in the source.
std::pair< SourceLocation, SourceLocation > getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
Options for controlling the compiler diagnostics engine.
virtual void beginDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
static void mapDiagnosticRanges(FullSourceLoc CaretLoc, ArrayRef< CharSourceRange > Ranges, SmallVectorImpl< CharSourceRange > &SpellingRanges)
std::pair< FullSourceLoc, StringRef > getModuleImportLoc() const
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
bool isTokenRange() const
Return true if the end of this range specifies the start of the last token.
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.
Dataflow Directional Tag Classes.
bool isValid() const
Return true if this is a valid SourceLocation object.
SourceLocation LastIncludeLoc
The location of the last include whose stack was printed if known.
const FullSourceLoc & getLocation() const
virtual void endDiagnostic(DiagOrStoredDiag D, DiagnosticsEngine::Level Level)
virtual void emitIncludeLocation(FullSourceLoc Loc, PresumedLoc PLoc)=0
static void mergeFixits(ArrayRef< FixItHint > FixItHints, const SourceManager &SM, const LangOptions &LangOpts, SmallVectorImpl< FixItHint > &MergedFixits)
FileID getFileID(SourceLocation SpellingLoc) const
Return the FileID for a SourceLocation.
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 commit(const Commit &commit)
SourceLocation getEnd() const
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.
void applyRewrites(EditsReceiver &receiver, bool adjustRemovals=true)
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...
FullSourceLoc getSpellingLoc() const
A SourceLocation and its associated SourceManager.
void emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) override
Annotates a diagnostic with some code that should be inserted, removed, or replaced to fix the proble...
A trivial tuple used to represent a source range.
SourceLocation getIncludeLoc() const
Return the presumed include location of this location.
std::pair< FullSourceLoc, FullSourceLoc > getImmediateExpansionRange() const
This class handles loading and caching of source files into memory.