20 #include "llvm/ADT/ArrayRef.h" 21 #include "llvm/ADT/DenseMap.h" 22 #include "llvm/ADT/None.h" 23 #include "llvm/ADT/SmallString.h" 24 #include "llvm/ADT/SmallVector.h" 25 #include "llvm/ADT/StringRef.h" 26 #include "llvm/Support/raw_ostream.h" 32 using namespace clang;
36 : LangOpts(LangOpts), DiagOpts(DiagOpts), LastLevel() {}
47 : MergedFixits(MergedFixits) {}
64 for (
const auto &Hint : FixItHints)
65 if (Hint.CodeToInsert.empty()) {
66 if (Hint.InsertFromRange.isValid())
68 Hint.InsertFromRange,
false,
69 Hint.BeforePreviousInsertions);
71 commit.
remove(Hint.RemoveRange);
73 if (Hint.RemoveRange.isTokenRange() ||
74 Hint.RemoveRange.getBegin() != Hint.RemoveRange.getEnd())
75 commit.
replace(Hint.RemoveRange, Hint.CodeToInsert);
77 commit.
insert(Hint.RemoveRange.getBegin(), Hint.CodeToInsert,
78 false, Hint.BeforePreviousInsertions);
82 if (Editor.
commit(commit)) {
83 FixitReceiver Rec(MergedFixits);
107 if (!FixItHints.empty()) {
109 FixItHints = MergedFixits;
112 for (
const auto &Hint : FixItHints)
113 if (Hint.RemoveRange.isValid())
114 MutableRanges.push_back(Hint.RemoveRange);
125 emitIncludeStack(Loc, PLoc, Level);
129 emitCaret(Loc, Level, MutableRanges, FixItHints);
134 emitMacroExpansions(UnexpandedLoc, Level, MutableRanges, FixItHints);
150 void DiagnosticRenderer::emitBasicNote(StringRef Message) {
182 emitIncludeStackRecursively(IncludeLoc);
185 emitImportStack(Loc);
191 void DiagnosticRenderer::emitIncludeStackRecursively(
FullSourceLoc Loc) {
205 if (!Imported.second.empty()) {
207 emitImportStackRecursively(Imported.first, Imported.second);
212 emitIncludeStackRecursively(
220 void DiagnosticRenderer::emitImportStack(
FullSourceLoc Loc) {
227 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
232 void DiagnosticRenderer::emitImportStackRecursively(
FullSourceLoc Loc,
233 StringRef ModuleName) {
234 if (ModuleName.empty()) {
242 emitImportStackRecursively(NextImportLoc.first, NextImportLoc.second);
250 void DiagnosticRenderer::emitModuleBuildStack(
const SourceManager &
SM) {
252 for (
const auto &I : Stack) {
266 bool &IsTokenRange) {
267 assert(SM->
getFileID(Loc) == MacroFileID);
268 if (MacroFileID == CaretFileID)
278 if (std::binary_search(CommonArgExpansions.begin(),
279 CommonArgExpansions.end(), MacroFileID))
291 if (MacroLocation.isValid()) {
292 MacroFileID = SM->
getFileID(MacroLocation);
293 bool TokenRange = IsBegin ? IsTokenRange : MacroRange.
isTokenRange();
296 CommonArgExpansions, IsBegin, SM, TokenRange);
297 if (MacroLocation.isValid()) {
298 IsTokenRange = TokenRange;
299 return MacroLocation;
310 MacroFileID = SM->
getFileID(MacroArgLocation);
312 CommonArgExpansions, IsBegin, SM, IsTokenRange);
326 Loc = IsBegin ? ExpRange.getBegin() : ExpRange.getEnd();
340 llvm::sort(BeginArgExpansions);
341 llvm::sort(EndArgExpansions);
342 std::set_intersection(BeginArgExpansions.begin(), BeginArgExpansions.end(),
343 EndArgExpansions.begin(), EndArgExpansions.end(),
344 std::back_inserter(CommonArgExpansions));
364 for (
const auto &Range : Ranges) {
365 if (Range.isInvalid())
369 bool IsTokenRange = Range.isTokenRange();
377 llvm::SmallDenseMap<FileID, SourceLocation> BeginLocsMap;
378 while (Begin.
isMacroID() && BeginFileID != EndFileID) {
379 BeginLocsMap[BeginFileID] =
Begin;
385 if (BeginFileID != EndFileID) {
386 while (
End.
isMacroID() && !BeginLocsMap.count(EndFileID)) {
393 Begin = BeginLocsMap[EndFileID];
394 BeginFileID = EndFileID;
402 CommonArgExpansions,
true, SM,
405 CommonArgExpansions,
false, SM,
429 void DiagnosticRenderer::emitSingleMacroExpansion(
441 llvm::raw_svector_ostream Message(MessageStorage);
444 if (MacroName.empty())
445 Message <<
"expanded from here";
447 Message <<
"expanded from macro '" << MacroName <<
"'";
450 SpellingRanges,
None);
461 if (ArgumentLoc == MacroLoc)
return true;
473 while (BegLoc != EndLoc) {
486 assert(Loc.
isMacroID() &&
"Must be a macro expansion!");
492 unsigned ValidCount = 0;
493 for (
const auto &Range : Ranges)
497 if (ValidCount > SpellingRanges.size())
508 for (
const auto &Range : SpellingRanges)
526 void DiagnosticRenderer::emitMacroExpansions(
FullSourceLoc Loc,
530 assert(Loc.
isValid() &&
"must have a valid source location here");
536 unsigned IgnoredEnd = 0;
540 if (SM.isMacroArgExpansion(L))
541 LocationStack.push_back(SM.getImmediateExpansionRange(L).getBegin());
543 LocationStack.push_back(L);
546 IgnoredEnd = LocationStack.size();
548 L = SM.getImmediateMacroCallerLoc(L);
554 L = SM.getImmediateMacroCallerLoc(LocationStack.back());
555 assert(L.
isValid() &&
"must have a valid source location here");
558 LocationStack.erase(LocationStack.begin(),
559 LocationStack.begin() + IgnoredEnd);
561 unsigned MacroDepth = LocationStack.size();
562 unsigned MacroLimit =
DiagOpts->MacroBacktraceLimit;
563 if (MacroDepth <= MacroLimit || MacroLimit == 0) {
564 for (
auto I = LocationStack.rbegin(), E = LocationStack.rend();
570 unsigned MacroStartMessages = MacroLimit / 2;
571 unsigned MacroEndMessages = MacroLimit / 2 + MacroLimit % 2;
573 for (
auto I = LocationStack.rbegin(),
574 E = LocationStack.rbegin() + MacroStartMessages;
579 llvm::raw_svector_ostream Message(MessageStorage);
580 Message <<
"(skipping " << (MacroDepth - MacroLimit)
581 <<
" expansions in backtrace; use -fmacro-backtrace-limit=0 to " 583 emitBasicNote(Message.str());
585 for (
auto I = LocationStack.rend() - MacroEndMessages,
586 E = LocationStack.rend();
597 llvm::raw_svector_ostream Message(MessageStorage);
598 Message <<
"in file included from " << PLoc.
getFilename() <<
':' 600 emitNote(Loc, Message.str());
605 StringRef ModuleName) {
608 llvm::raw_svector_ostream Message(MessageStorage);
609 Message <<
"in module '" << ModuleName;
611 Message <<
"' imported from " << PLoc.
getFilename() <<
':' 614 emitNote(Loc, Message.str());
619 StringRef ModuleName) {
622 llvm::raw_svector_ostream Message(MessageStorage);
624 Message <<
"while building module '" << ModuleName <<
"' imported from " 627 Message <<
"while building module '" << ModuleName <<
"':";
628 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.