19 #include "llvm/ADT/ArrayRef.h" 20 #include "llvm/ADT/DenseMap.h" 21 #include "llvm/ADT/None.h" 22 #include "llvm/ADT/SmallString.h" 23 #include "llvm/ADT/SmallVector.h" 24 #include "llvm/ADT/StringRef.h" 25 #include "llvm/Support/raw_ostream.h" 31 using namespace clang;
35 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
46 : MergedFixits(MergedFixits) {}
63 for (
const auto &Hint : FixItHints)
64 if (Hint.CodeToInsert.empty()) {
65 if (Hint.InsertFromRange.isValid())
67 Hint.InsertFromRange,
false,
68 Hint.BeforePreviousInsertions);
70 commit.
remove(Hint.RemoveRange);
72 if (Hint.RemoveRange.isTokenRange() ||
73 Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
74 commit.
replace(Hint.RemoveRange, Hint.CodeToInsert);
76 commit.
insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
77 false, Hint.BeforePreviousInsertions);
81 if (Editor.
commit(commit)) {
82 FixitReceiver Rec(MergedFixits);
106 if (!FixItHints.empty()) {
108 FixItHints = MergedFixits;
111 for (
const auto &Hint : FixItHints)
112 if (Hint.RemoveRange.isValid())
113 MutableRanges.push_back(Hint.RemoveRange);
124 emitIncludeStack(Loc, PLoc, Level);
128 emitCaret(Loc, Level, MutableRanges, FixItHints);
133 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
149 void DiagnosticRenderer::emitBasicNote(StringRef Message) {
181 emitIncludeStackRecursively(IncludeLoc);
184 emitImportStack(Loc);
190 void DiagnosticRenderer::emitIncludeStackRecursively(
FullSourceLoc Loc) {
204 if (!Imported.second.empty()) {
206 emitImportStackRecursively(Imported.first, Imported.second);
211 emitIncludeStackRecursively(
219 void DiagnosticRenderer::emitImportStack(
FullSourceLoc Loc) {
226 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
231 void DiagnosticRenderer::emitImportStackRecursively(
FullSourceLoc Loc,
232 StringRef ModuleName) {
233 if (ModuleName.empty()) {
241 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
249 void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &
SM) {
251 for (
const auto &I : Stack) {
265 bool &IsTokenRange) {
266 assert(SM->
getFileID(Loc) == MacroFileID);
267 if (MacroFileID == CaretFileID)
277 if (std::binary_search(CommonArgExpansions.begin(),
278 CommonArgExpansions.end(), MacroFileID))
290 if (MacroLocation.isValid()) {
291 MacroFileID = SM->
getFileID(MacroLocation);
292 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.
isTokenRange();
295 CommonArgExpansions, IsBegin, SM, TokenRange);
296 if (MacroLocation.isValid()) {
297 IsTokenRange = TokenRange;
298 return MacroLocation;
309 MacroFileID = SM->
getFileID(MacroArgLocation);
311 CommonArgExpansions, IsBegin, SM, IsTokenRange);
325 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
339 llvm::sort(BeginArgExpansions);
340 llvm::sort(EndArgExpansions);
341 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
342 EndArgExpansions.begin(), EndArgExpansions.end(),
343 std::back_inserter(CommonArgExpansions));
363 for (
const auto &Range : Ranges) {
364 if (Range.isInvalid())
368 bool IsTokenRange = Range.isTokenRange();
376 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
377 while (Begin.
isMacroID() && BeginFileID != EndFileID) {
378 BeginLocsMap[BeginFileID] =
Begin;
384 if (BeginFileID != EndFileID) {
385 while (
End.
isMacroID() && !BeginLocsMap.count(EndFileID)) {
392 Begin = BeginLocsMap[EndFileID];
393 BeginFileID = EndFileID;
401 CommonArgExpansions,
true, SM,
404 CommonArgExpansions,
false, SM,
428 void DiagnosticRenderer::emitSingleMacroExpansion(
440 llvm::raw_svector_ostream Message(MessageStorage);
443 if (MacroName.empty())
444 Message <<
"expanded from here";
446 Message <<
"expanded from macro '" << MacroName <<
"'";
449 SpellingRanges,
None);
460 if (ArgumentLoc == MacroLoc)
return true;
472 while (BegLoc != EndLoc) {
485 assert(Loc.
isMacroID() &&
"Must be a macro expansion!");
491 unsigned ValidCount = 0;
492 for (
const auto &Range : Ranges)
496 if (ValidCount > SpellingRanges.size())
507 for (
const auto &Range : SpellingRanges)
525 void DiagnosticRenderer::emitMacroExpansions(
FullSourceLoc Loc,
529 assert(Loc.
isValid() &&
"must have a valid source location here");
535 unsigned IgnoredEnd = 0;
539 if (SM.isMacroArgExpansion(L))
540 LocationStack.push_back(SM.getImmediateExpansionRange(L).getBegin());
542 LocationStack.push_back(L);
545 IgnoredEnd = LocationStack.size();
547 L = SM.getImmediateMacroCallerLoc(L);
553 L = SM.getImmediateMacroCallerLoc(LocationStack.back());
554 assert(L.
isValid() &&
"must have a valid source location here");
557 LocationStack.erase(LocationStack.begin(),
558 LocationStack.begin() + IgnoredEnd);
560 unsigned MacroDepth = LocationStack.size();
561 unsigned MacroLimit =
DiagOpts->MacroBacktraceLimit;
562 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
563 for (
auto I = LocationStack.rbegin(), E = LocationStack.rend();
569 unsigned MacroStartMessages = MacroLimit / 2;
570 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
572 for (
auto I = LocationStack.rbegin(),
573 E = LocationStack.rbegin() + MacroStartMessages;
578 llvm::raw_svector_ostream Message(MessageStorage);
579 Message <<
"(skipping " << (MacroDepth - MacroLimit)
580 <<
" expansions in backtrace; use -fmacro-backtrace-limit=0 to " 582 emitBasicNote(Message.str());
584 for (
auto I = LocationStack.rend() - MacroEndMessages,
585 E = LocationStack.rend();
596 llvm::raw_svector_ostream Message(MessageStorage);
597 Message <<
"in file included from " << PLoc.
getFilename() <<
':' 599 emitNote(Loc, Message.str());
604 StringRef ModuleName) {
607 llvm::raw_svector_ostream Message(MessageStorage);
608 Message <<
"in module '" << ModuleName;
610 Message <<
"' imported from " << PLoc.
getFilename() <<
':' 613 emitNote(Loc, Message.str());
618 StringRef ModuleName) {
621 llvm::raw_svector_ostream Message(MessageStorage);
623 Message <<
"while building module '" << ModuleName <<
"' imported from " 626 Message <<
"while building module '" << ModuleName <<
"':";
627 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)
llvm::PointerUnion< const Diagnostic *, const StoredDiagnostic * > DiagOrStoredDiag
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 the expansio...
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
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.
Forward-declares and imports various common LLVM datatypes that clang wants to use unqualified...
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
Defines the Diagnostic-related interfaces.
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
CharSourceRange getImmediateExpansionRange(SourceLocation Loc) const
Return the start/end of the expansion information for an expansion location.
IntrusiveRefCntPtr< DiagnosticOptions > DiagOpts
Represents an unpacked "presumed" location which can be presented to the user.
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.
Encodes a location in the source.
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)
Defines the clang::SourceLocation class and associated facilities.
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
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.
A trivial tuple used to represent a source range.
SourceLocation getIncludeLoc() const
Return the presumed include location of this location.
This class handles loading and caching of source files into memory.