19 #include "llvm/ADT/SmallString.h"
20 #include "llvm/ADT/StringExtras.h"
21 #include "llvm/Support/CrashRecoveryContext.h"
22 #include "llvm/Support/Locale.h"
23 #include "llvm/Support/raw_ostream.h"
25 using namespace clang;
30 switch (nullability.first) {
32 string = nullability.second ?
"'nonnull'" :
"'_Nonnull'";
36 string = nullability.second ?
"'nullable'" :
"'_Nullable'";
40 string = nullability.second ?
"'null_unspecified'" :
"'_Null_unspecified'";
49 StringRef Modifier, StringRef Argument,
54 StringRef Str =
"<can't format argument>";
55 Output.append(Str.begin(), Str.end());
58 DiagnosticsEngine::DiagnosticsEngine(
61 : Diags(diags), DiagOpts(DiagOpts), Client(nullptr),
SourceMgr(nullptr) {
64 ArgToStringCookie =
nullptr;
66 AllExtensionsSilenced = 0;
67 IgnoreAllWarnings =
false;
68 WarningsAsErrors =
false;
69 EnableAllWarnings =
false;
70 ErrorsAsFatal =
false;
71 SuppressSystemWarnings =
false;
72 SuppressAllDiagnostics =
false;
74 PrintTemplateTree =
false;
80 TemplateBacktraceLimit = 0;
81 ConstexprBacktraceLimit = 0;
93 bool ShouldOwnClient) {
94 Owner.reset(ShouldOwnClient ? client :
nullptr);
99 DiagStateOnPushStack.push_back(GetCurDiagState());
103 if (DiagStateOnPushStack.empty())
106 if (DiagStateOnPushStack.back() != GetCurDiagState()) {
108 PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
110 DiagStateOnPushStack.pop_back();
115 ErrorOccurred =
false;
116 UncompilableErrorOccurred =
false;
117 FatalErrorOccurred =
false;
118 UnrecoverableErrorOccurred =
false;
122 TrapNumErrorsOccurred = 0;
123 TrapNumUnrecoverableErrorsOccurred = 0;
131 DiagStatePoints.clear();
132 DiagStateOnPushStack.clear();
136 DiagStates.emplace_back();
137 DiagStatePoints.push_back(DiagStatePoint(&DiagStates.back(),
FullSourceLoc()));
145 DelayedDiagID = DiagID;
146 DelayedDiagArg1 = Arg1.str();
147 DelayedDiagArg2 = Arg2.str();
150 void DiagnosticsEngine::ReportDelayed() {
151 Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
153 DelayedDiagArg1.clear();
154 DelayedDiagArg2.clear();
157 DiagnosticsEngine::DiagStatePointsTy::iterator
158 DiagnosticsEngine::GetDiagStatePointForLoc(
SourceLocation L)
const {
159 assert(!DiagStatePoints.empty());
160 assert(DiagStatePoints.front().Loc.isInvalid() &&
161 "Should have created a DiagStatePoint for command-line");
164 return DiagStatePoints.end() - 1;
168 return DiagStatePoints.end() - 1;
170 DiagStatePointsTy::iterator Pos = DiagStatePoints.end();
171 FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
172 if (LastStateChangePos.
isValid() &&
173 Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
174 Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
175 DiagStatePoint(
nullptr, Loc));
183 "Can only map builtin diagnostics");
184 assert((Diags->isBuiltinWarningOrExtension(Diag) ||
186 "Cannot map errors into warnings!");
187 assert(!DiagStatePoints.empty());
188 assert((L.
isInvalid() || SourceMgr) &&
"No SourceMgr for valid location");
191 FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
202 if (Loc.
isInvalid() || Loc == LastStateChangePos) {
203 GetCurDiagState()->setMapping(Diag, Mapping);
214 DiagStates.push_back(*GetCurDiagState());
215 PushDiagStatePoint(&DiagStates.back(), Loc);
216 GetCurDiagState()->setMapping(Diag, Mapping);
223 DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
224 assert(Pos != DiagStatePoints.end());
227 for (DiagStatePointsTy::iterator
228 I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
229 GetCurDiagState()->setMapping(Diag, Mapping);
233 if (Pos->Loc == Loc) {
234 GetCurDiagState()->setMapping(Diag, Mapping);
240 assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc));
241 DiagStates.push_back(*Pos->State);
242 DiagState *NewState = &DiagStates.back();
243 GetCurDiagState()->setMapping(Diag, Mapping);
244 DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
245 FullSourceLoc(Loc, *SourceMgr)));
253 if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
281 for (
unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
312 for (
unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
329 Diags->getAllDiagnostics(Flavor, AllDiags);
332 for (
unsigned i = 0, e = AllDiags.size(); i != e; ++i)
333 if (Diags->isBuiltinWarningOrExtension(AllDiags[i]))
338 assert(CurDiagID == ~0U &&
"Multiple diagnostics in flight at once!");
341 CurDiagID = storedDiag.
getID();
347 DiagFixItHints.clear();
350 assert(Client &&
"DiagnosticConsumer not set!");
363 assert(
getClient() &&
"DiagnosticClient not set!");
376 Diags->EmitDiag(*
this, DiagLevel);
381 Emitted = ProcessDiag();
385 unsigned DiagID = CurDiagID;
389 if (!Force && DelayedDiagID && DelayedDiagID != DiagID)
410 template <std::
size_t StrLen>
411 static bool ModifierIs(
const char *Modifier,
unsigned ModifierLen,
412 const char (&Str)[StrLen]) {
413 return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
418 static const char *
ScanFormat(
const char *I,
const char *E,
char Target) {
421 for ( ; I != E; ++I) {
422 if (Depth == 0 && *I == Target)
return I;
423 if (Depth != 0 && *I ==
'}') Depth--;
433 for (I++; I != E && !
isDigit(*I) && *I !=
'{'; I++) ;
449 const char *Argument,
unsigned ArgumentLen,
451 const char *ArgumentEnd = Argument+ArgumentLen;
455 const char *NextVal =
ScanFormat(Argument, ArgumentEnd,
'|');
456 assert(NextVal != ArgumentEnd &&
"Value for integer select modifier was"
457 " larger than the number of options in the diagnostic string!");
458 Argument = NextVal+1;
463 const char *EndPtr =
ScanFormat(Argument, ArgumentEnd,
'|');
475 OutStr.push_back(
's');
484 assert(ValNo != 0 &&
"ValNo must be strictly positive!");
486 llvm::raw_svector_ostream Out(OutStr);
490 Out << ValNo << llvm::getOrdinalSuffix(ValNo);
498 while (Start != End && *Start >=
'0' && *Start <=
'9') {
515 assert(*Start ==
',' &&
"Bad plural expression syntax: expected ,");
518 assert(*Start ==
']' &&
"Bad plural expression syntax: expected )");
520 return Low <= Val && Val <= High;
535 assert(*Start ==
'=' &&
"Bad plural expression syntax: expected =");
537 unsigned ValMod = ValNo % Arg;
541 assert((C ==
'[' || (C >=
'0' && C <=
'9')) &&
542 "Bad plural expression syntax: unexpected character");
549 Start = std::find(Start, End,
',');
591 const char *Argument,
unsigned ArgumentLen,
593 const char *ArgumentEnd = Argument + ArgumentLen;
595 assert(Argument < ArgumentEnd &&
"Plural expression didn't match.");
596 const char *ExprEnd = Argument;
597 while (*ExprEnd !=
':') {
598 assert(ExprEnd != ArgumentEnd &&
"Plural missing expression end");
602 Argument = ExprEnd + 1;
603 ExprEnd =
ScanFormat(Argument, ArgumentEnd,
'|');
610 Argument =
ScanFormat(Argument, ArgumentEnd - 1,
'|') + 1;
619 case tok::identifier:
631 if (!StoredDiagMessage.empty()) {
632 OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
649 if (DiagEnd - DiagStr == 2 &&
650 StringRef(DiagStr, DiagEnd - DiagStr).
equals(
"%0") &&
654 if (llvm::sys::locale::isPrint(c) || c ==
'\t') {
672 for (
unsigned i = 0, e =
getNumArgs(); i < e; ++i)
676 while (DiagStr != DiagEnd) {
677 if (DiagStr[0] !=
'%') {
679 const char *StrEnd = std::find(DiagStr, DiagEnd,
'%');
680 OutStr.append(DiagStr, StrEnd);
684 OutStr.push_back(DiagStr[1]);
697 const char *Modifier =
nullptr, *Argument =
nullptr;
698 unsigned ModifierLen = 0, ArgumentLen = 0;
703 while (DiagStr[0] ==
'-' ||
704 (DiagStr[0] >=
'a' && DiagStr[0] <=
'z'))
706 ModifierLen = DiagStr-Modifier;
709 if (DiagStr[0] ==
'{') {
714 assert(DiagStr != DiagEnd &&
"Mismatched {}'s in diagnostic string!");
715 ArgumentLen = DiagStr-Argument;
720 assert(
isDigit(*DiagStr) &&
"Invalid format for argument in diagnostic");
721 unsigned ArgNo = *DiagStr++ -
'0';
724 unsigned ArgNo2 = ArgNo;
727 if (
ModifierIs(Modifier, ModifierLen,
"diff")) {
728 assert(*DiagStr ==
',' &&
isDigit(*(DiagStr + 1)) &&
729 "Invalid format for diff modifier");
731 ArgNo2 = *DiagStr++ -
'0';
742 const char *Pipe =
ScanFormat(Argument, Argument + ArgumentLen,
'|');
743 const char *FirstDollar =
ScanFormat(Argument, Pipe,
'$');
744 const char *SecondDollar =
ScanFormat(FirstDollar + 1, Pipe,
'$');
745 const char ArgStr1[] = {
'%',
static_cast<char>(
'0' + ArgNo) };
746 const char ArgStr2[] = {
'%',
static_cast<char>(
'0' + ArgNo2) };
760 assert(ModifierLen == 0 &&
"No modifiers for strings yet");
761 OutStr.append(S.begin(), S.end());
766 assert(ModifierLen == 0 &&
"No modifiers for strings yet");
772 OutStr.append(S, S + strlen(S));
779 if (
ModifierIs(Modifier, ModifierLen,
"select")) {
782 }
else if (
ModifierIs(Modifier, ModifierLen,
"s")) {
784 }
else if (
ModifierIs(Modifier, ModifierLen,
"plural")) {
787 }
else if (
ModifierIs(Modifier, ModifierLen,
"ordinal")) {
790 assert(ModifierLen == 0 &&
"Unknown integer modifier");
791 llvm::raw_svector_ostream(OutStr) << Val;
798 if (
ModifierIs(Modifier, ModifierLen,
"select")) {
800 }
else if (
ModifierIs(Modifier, ModifierLen,
"s")) {
802 }
else if (
ModifierIs(Modifier, ModifierLen,
"plural")) {
805 }
else if (
ModifierIs(Modifier, ModifierLen,
"ordinal")) {
808 assert(ModifierLen == 0 &&
"Unknown integer modifier");
809 llvm::raw_svector_ostream(OutStr) << Val;
816 assert(ModifierLen == 0 &&
"No modifiers for token kinds yet");
818 llvm::raw_svector_ostream Out(OutStr);
821 Out <<
'\'' <<
S <<
'\'';
830 Out << '<' << S << '>
';
835 // ---- NAMES and TYPES ----
836 case DiagnosticsEngine::ak_identifierinfo: {
837 const IdentifierInfo *II = getArgIdentifier(ArgNo);
838 assert(ModifierLen == 0 && "No modifiers for strings yet");
840 // Don't crash
if get passed a null pointer by accident.
842 const char *S =
"(null)";
843 OutStr.append(S, S + strlen(S));
847 llvm::raw_svector_ostream(OutStr) <<
'\'' << II->getName() <<
'\'';
857 StringRef(Modifier, ModifierLen),
858 StringRef(Argument, ArgumentLen),
860 OutStr, QualTypeVals);
870 intptr_t val =
reinterpret_cast<intptr_t
>(&TDT);
872 const char *ArgumentEnd = Argument + ArgumentLen;
873 const char *Pipe =
ScanFormat(Argument, ArgumentEnd,
'|');
877 if (
getDiags()->PrintTemplateTree && Tree.empty()) {
881 StringRef(Modifier, ModifierLen),
882 StringRef(Argument, ArgumentLen),
894 const char *FirstDollar =
ScanFormat(Argument, ArgumentEnd,
'$');
895 const char *SecondDollar =
ScanFormat(FirstDollar + 1, ArgumentEnd,
'$');
904 StringRef(Modifier, ModifierLen),
905 StringRef(Argument, ArgumentLen),
907 OutStr, QualTypeVals);
918 StringRef(Modifier, ModifierLen),
919 StringRef(Argument, ArgumentLen),
921 OutStr, QualTypeVals);
937 FormattedArgs.push_back(std::make_pair(Kind,
getRawArg(ArgNo)));
945 OutStr.append(Tree.begin(), Tree.end());
952 : ID(ID), Level(Level), Loc(), Message(Message) { }
956 :
ID(Info.getID()), Level(Level)
959 "Valid source location without setting a source manager for diagnostic");
964 this->Message.assign(Message.begin(), Message.end());
973 : ID(ID), Level(Level), Loc(Loc), Message(Message),
974 Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
986 void IgnoringDiagConsumer::anchor() { }
1006 for (
unsigned I = 0; I != NumCached; ++I)
1007 FreeList[I] = Cached + I;
1008 NumFreeListEntries = NumCached;
1014 assert((NumFreeListEntries == NumCached ||
1015 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1016 "A partial is on the lamb");
void setSeverityForAll(diag::Flavor Flavor, diag::Severity Map, SourceLocation Loc=SourceLocation())
Add the specified mapping to all diagnostics of the specified flavor.
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.
static LLVM_READONLY bool isDigit(unsigned char c)
Return true if this character is an ASCII digit: [0-9].
DiagnosticConsumer * getClient()
void pushMappings(SourceLocation Loc)
Copies the current DiagMappings and pushes the new copy onto the top of the stack.
unsigned getNumArgs() const
unsigned NumErrors
Number of errors reported.
StringRef getMessage() const
const std::string & getArgStdStr(unsigned Idx) const
Return the provided argument string specified by Idx.
static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT, StringRef Modifier, StringRef Argument, ArrayRef< DiagnosticsEngine::ArgumentValue > PrevArgs, SmallVectorImpl< char > &Output, void *Cookie, ArrayRef< intptr_t > QualTypeVals)
Represents a diagnostic in a form that can be retained until its corresponding source manager is dest...
const DiagnosticBuilder & operator<<(const DiagnosticBuilder &DB, const Attr *At)
void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info) override
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
const FullSourceLoc & getLocation() const
static const char * ScanFormat(const char *I, const char *E, char Target)
DiagnosticBuilder Report(SourceLocation Loc, unsigned DiagID)
Issue the message to the client.
static const char * getTokenDescForDiagnostic(tok::TokenKind Kind)
Returns the friendly description for a token kind that will appear without quotes in diagnostic messa...
void ConvertArgToString(ArgumentKind Kind, intptr_t Val, StringRef Modifier, StringRef Argument, ArrayRef< ArgumentValue > PrevArgs, SmallVectorImpl< char > &Output, ArrayRef< intptr_t > QualTypeVals) const
Converts a diagnostic argument (as an intptr_t) into the string that represents it.
bool setDiagnosticGroupWarningAsError(StringRef Group, bool Enabled)
Set the warning-as-error flag for the given diagnostic group.
Abstract interface, implemented by clients of the front-end, which formats and prints fully processed...
void SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1="", StringRef Arg2="")
Set the "delayed" diagnostic that will be emitted once the current diagnostic completes.
fixit_iterator fixit_end() const
void setClient(DiagnosticConsumer *client, bool ShouldOwnClient=true)
Set the diagnostic client associated with this diagnostic object.
const DiagnosticsEngine * getDiags() const
bool setDiagnosticGroupErrorAsFatal(StringRef Group, bool Enabled)
Set the error-as-fatal flag for the given diagnostic group.
int getArgSInt(unsigned Idx) const
Return the specified signed integer argument.
std::pair< NullabilityKind, bool > DiagNullabilityKind
Values of this type can be null.
const char * getKeywordSpelling(TokenKind Kind) LLVM_READNONE
Determines the spelling of simple keyword and contextual keyword tokens like 'int' and 'dynamic_cast'...
const SourceLocation & getLocation() const
virtual bool IncludeInDiagnosticCounts() const
Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...
bool setSeverityForGroup(diag::Flavor Flavor, StringRef Group, diag::Severity Map, SourceLocation Loc=SourceLocation())
Change an entire diagnostic group (e.g. "unknown-pragmas") to have the specified mapping.
Values of this type can never be null.
fixit_iterator fixit_begin() const
Present this diagnostic as an error.
const char * getArgCStr(unsigned Idx) const
Return the specified C string argument.
const IntrusiveRefCntPtr< DiagnosticIDs > & getDiagnosticIDs() const
void Reset()
Reset the state of the diagnostic object to its initial configuration.
bool IncludeInDiagnosticCounts() const override
Indicates whether the diagnostics handled by this DiagnosticConsumer should be included in the number...
bool EmitCurrentDiagnostic(bool Force=false)
Emit the current diagnostic and clear the diagnostic state.
A little helper class used to produce diagnostics.
ID
Defines the set of possible language-specific address spaces.
virtual ~DiagnosticConsumer()
bool equals(const til::SExpr *E1, const til::SExpr *E2)
range_iterator range_begin() const
static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End)
EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
unsigned TemplateDiffUsed
intptr_t getRawArg(unsigned Idx) const
Return the specified non-string argument in an opaque form.
const char * getPunctuatorSpelling(TokenKind Kind) LLVM_READNONE
Determines the spelling of simple punctuation tokens like '!' or '', and returns NULL for literal and...
static void HandleOrdinalModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
Defines the clang::IdentifierInfo, clang::IdentifierTable, and clang::Selector interfaces.
void AddString(StringRef S) const
void Clear()
Clear out the current diagnostic.
diag::Severity getSeverity() const
Encodes a location in the source. The SourceManager can decode this to get at the full include stack...
bool isValid() const
Return true if this is a valid SourceLocation object.
Options for controlling the compiler diagnostics engine.
static bool ModifierIs(const char *Modifier, unsigned ModifierLen, const char(&Str)[StrLen])
ModifierIs - Return true if the specified modifier matches specified string.
static LLVM_READONLY bool isPunctuation(unsigned char c)
TokenKind
Provides a simple uniform namespace for tokens from all C languages.
unsigned NumWarnings
Number of warnings reported.
void setNoErrorAsFatal(bool Value)
~ForwardingDiagnosticConsumer() override
virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const Diagnostic &Info)
Handle this diagnostic, reporting it to the user or capturing it to a log as needed.
DiagnosticsEngine::ArgumentKind getArgKind(unsigned Idx) const
Return the kind of the specified index.
static unsigned PluralNumber(const char *&Start, const char *End)
PluralNumber - Parse an unsigned integer and advance Start.
static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)
range_iterator range_end() const
bool hasSourceManager() const
Level
The level of the diagnostic, after it has been through mapping.
ArrayRef< CharSourceRange > getRanges() const
Return an array reference for this diagnostic's ranges.
static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo, const char *Argument, unsigned ArgumentLen, SmallVectorImpl< char > &OutStr)
Defines the Diagnostic-related interfaces.
static void HandleIntegerSModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
SourceManager & getSourceManager() const
void setSeverity(diag::kind Diag, diag::Severity Map, SourceLocation Loc)
This allows the client to specify that certain warnings are ignored.
bool popMappings(SourceLocation Loc)
Pops the current DiagMappings off the top of the stack, causing the new top of the stack to be the ac...
Implements a partial diagnostic that can be emitted anwyhere in a DiagnosticBuilder stream...
void setSeverity(diag::Severity Value)
bool isBeforeInTranslationUnitThan(SourceLocation Loc) const
Determines the order of 2 source locations in the translation unit.
Level
The level of the diagnostic, after it has been through mapping.
Do not present this diagnostic, ignore it.
DiagnosticsEngine::Level getLevel() const
const char * getTokenName(TokenKind Kind) LLVM_READNONE
Determines the name of a token as used within the front end.
A SourceLocation and its associated SourceManager.
unsigned getArgUInt(unsigned Idx) const
Return the specified unsigned integer argument.
Present this diagnostic as a fatal error.
void setNoWarningAsError(bool Value)
void FormatDiagnostic(SmallVectorImpl< char > &OutStr) const
Format this diagnostic into a string, substituting the formal arguments into the %0 slots...
Present this diagnostic as a warning.
ArrayRef< FixItHint > getFixItHints() const
static bool TestPluralRange(unsigned Val, const char *&Start, const char *End)
TestPluralRange - Test if Val is in the parsed range. Modifies Start.
enum TokenKind : unsigned