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 FatalsAsError =
false;
72 SuppressSystemWarnings =
false;
73 SuppressAllDiagnostics =
false;
75 PrintTemplateTree =
false;
81 TemplateBacktraceLimit = 0;
82 ConstexprBacktraceLimit = 0;
94 bool ShouldOwnClient) {
95 Owner.reset(ShouldOwnClient ? client :
nullptr);
100 DiagStateOnPushStack.push_back(GetCurDiagState());
104 if (DiagStateOnPushStack.empty())
107 if (DiagStateOnPushStack.back() != GetCurDiagState()) {
109 PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
111 DiagStateOnPushStack.pop_back();
116 ErrorOccurred =
false;
117 UncompilableErrorOccurred =
false;
118 FatalErrorOccurred =
false;
119 UnrecoverableErrorOccurred =
false;
123 TrapNumErrorsOccurred = 0;
124 TrapNumUnrecoverableErrorsOccurred = 0;
132 DiagStatePoints.clear();
133 DiagStateOnPushStack.clear();
137 DiagStates.emplace_back();
138 DiagStatePoints.push_back(DiagStatePoint(&DiagStates.back(),
FullSourceLoc()));
146 DelayedDiagID = DiagID;
147 DelayedDiagArg1 = Arg1.str();
148 DelayedDiagArg2 = Arg2.str();
151 void DiagnosticsEngine::ReportDelayed() {
152 Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
154 DelayedDiagArg1.clear();
155 DelayedDiagArg2.clear();
159 DiagnosticsEngine::GetDiagStatePointForLoc(
SourceLocation L)
const {
160 assert(!DiagStatePoints.empty());
161 assert(DiagStatePoints.front().Loc.isInvalid() &&
162 "Should have created a DiagStatePoint for command-line");
165 return DiagStatePoints.end() - 1;
169 return DiagStatePoints.end() - 1;
172 FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
173 if (LastStateChangePos.
isValid() &&
174 Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
175 Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
176 DiagStatePoint(
nullptr, Loc));
184 "Can only map builtin diagnostics");
185 assert((Diags->isBuiltinWarningOrExtension(Diag) ||
187 "Cannot map errors into warnings!");
188 assert(!DiagStatePoints.empty());
189 assert((L.
isInvalid() || SourceMgr) &&
"No SourceMgr for valid location");
192 FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
203 if (Loc.
isInvalid() || Loc == LastStateChangePos) {
204 GetCurDiagState()->setMapping(Diag, Mapping);
215 DiagStates.push_back(*GetCurDiagState());
216 PushDiagStatePoint(&DiagStates.back(), Loc);
217 GetCurDiagState()->setMapping(Diag, Mapping);
225 assert(Pos != DiagStatePoints.end());
229 I = Pos+1,
E = DiagStatePoints.end();
I !=
E; ++
I) {
230 I->State->setMapping(Diag, Mapping);
234 if (Pos->Loc == Loc) {
235 Pos->State->setMapping(Diag, Mapping);
241 assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc));
242 DiagStates.push_back(*Pos->State);
243 DiagState *NewState = &DiagStates.back();
244 NewState->setMapping(Diag, Mapping);
245 DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
246 FullSourceLoc(Loc, *SourceMgr)));
254 if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
330 Diags->getAllDiagnostics(Flavor, AllDiags);
334 if (Diags->isBuiltinWarningOrExtension(
Diag))
339 assert(CurDiagID == ~0U &&
"Multiple diagnostics in flight at once!");
342 CurDiagID = storedDiag.
getID();
348 DiagFixItHints.clear();
351 assert(Client &&
"DiagnosticConsumer not set!");
364 assert(
getClient() &&
"DiagnosticClient not set!");
377 Diags->EmitDiag(*
this, DiagLevel);
382 Emitted = ProcessDiag();
386 unsigned DiagID = CurDiagID;
390 if (!Force && DelayedDiagID && DelayedDiagID != DiagID)
411 template <std::
size_t StrLen>
413 const char (&Str)[StrLen]) {
414 return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
419 static const char *
ScanFormat(
const char *
I,
const char *
E,
char Target) {
422 for ( ; I !=
E; ++
I) {
423 if (Depth == 0 && *I == Target)
return I;
424 if (Depth != 0 && *I ==
'}') Depth--;
434 for (I++; I != E && !
isDigit(*I) && *I !=
'{'; I++) ;
450 const char *Argument,
unsigned ArgumentLen,
452 const char *ArgumentEnd = Argument+ArgumentLen;
456 const char *NextVal =
ScanFormat(Argument, ArgumentEnd,
'|');
457 assert(NextVal != ArgumentEnd &&
"Value for integer select modifier was"
458 " larger than the number of options in the diagnostic string!");
459 Argument = NextVal+1;
464 const char *EndPtr =
ScanFormat(Argument, ArgumentEnd,
'|');
476 OutStr.push_back(
's');
485 assert(ValNo != 0 &&
"ValNo must be strictly positive!");
487 llvm::raw_svector_ostream Out(OutStr);
491 Out << ValNo << llvm::getOrdinalSuffix(ValNo);
499 while (Start != End && *Start >=
'0' && *Start <=
'9') {
516 assert(*Start ==
',' &&
"Bad plural expression syntax: expected ,");
519 assert(*Start ==
']' &&
"Bad plural expression syntax: expected )");
521 return Low <= Val && Val <= High;
536 assert(*Start ==
'=' &&
"Bad plural expression syntax: expected =");
538 unsigned ValMod = ValNo % Arg;
542 assert((C ==
'[' || (C >=
'0' && C <=
'9')) &&
543 "Bad plural expression syntax: unexpected character");
550 Start = std::find(Start, End,
',');
592 const char *Argument,
unsigned ArgumentLen,
594 const char *ArgumentEnd = Argument + ArgumentLen;
596 assert(Argument < ArgumentEnd &&
"Plural expression didn't match.");
597 const char *ExprEnd = Argument;
598 while (*ExprEnd !=
':') {
599 assert(ExprEnd != ArgumentEnd &&
"Plural missing expression end");
603 Argument = ExprEnd + 1;
604 ExprEnd =
ScanFormat(Argument, ArgumentEnd,
'|');
611 Argument =
ScanFormat(Argument, ArgumentEnd - 1,
'|') + 1;
620 case tok::identifier:
632 if (!StoredDiagMessage.empty()) {
633 OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
650 if (DiagEnd - DiagStr == 2 &&
651 StringRef(DiagStr, DiagEnd - DiagStr).
equals(
"%0") &&
655 if (llvm::sys::locale::isPrint(c) || c ==
'\t') {
673 for (
unsigned i = 0, e =
getNumArgs(); i < e; ++i)
677 while (DiagStr != DiagEnd) {
678 if (DiagStr[0] !=
'%') {
680 const char *StrEnd = std::find(DiagStr, DiagEnd,
'%');
681 OutStr.append(DiagStr, StrEnd);
685 OutStr.push_back(DiagStr[1]);
698 const char *Modifier =
nullptr, *Argument =
nullptr;
699 unsigned ModifierLen = 0, ArgumentLen = 0;
704 while (DiagStr[0] ==
'-' ||
705 (DiagStr[0] >=
'a' && DiagStr[0] <=
'z'))
710 if (DiagStr[0] ==
'{') {
715 assert(DiagStr != DiagEnd &&
"Mismatched {}'s in diagnostic string!");
716 ArgumentLen = DiagStr-Argument;
721 assert(
isDigit(*DiagStr) &&
"Invalid format for argument in diagnostic");
722 unsigned ArgNo = *DiagStr++ -
'0';
725 unsigned ArgNo2 = ArgNo;
728 if (
ModifierIs(Modifier, ModifierLen,
"diff")) {
729 assert(*DiagStr ==
',' &&
isDigit(*(DiagStr + 1)) &&
730 "Invalid format for diff modifier");
732 ArgNo2 = *DiagStr++ -
'0';
743 const char *Pipe =
ScanFormat(Argument, Argument + ArgumentLen,
'|');
744 const char *FirstDollar =
ScanFormat(Argument, Pipe,
'$');
745 const char *SecondDollar =
ScanFormat(FirstDollar + 1, Pipe,
'$');
746 const char ArgStr1[] = {
'%',
static_cast<char>(
'0' + ArgNo) };
747 const char ArgStr2[] = {
'%',
static_cast<char>(
'0' + ArgNo2) };
761 assert(ModifierLen == 0 &&
"No modifiers for strings yet");
762 OutStr.append(S.begin(), S.end());
767 assert(ModifierLen == 0 &&
"No modifiers for strings yet");
773 OutStr.append(S, S + strlen(S));
780 if (
ModifierIs(Modifier, ModifierLen,
"select")) {
783 }
else if (
ModifierIs(Modifier, ModifierLen,
"s")) {
785 }
else if (
ModifierIs(Modifier, ModifierLen,
"plural")) {
788 }
else if (
ModifierIs(Modifier, ModifierLen,
"ordinal")) {
791 assert(ModifierLen == 0 &&
"Unknown integer modifier");
792 llvm::raw_svector_ostream(OutStr) << Val;
799 if (
ModifierIs(Modifier, ModifierLen,
"select")) {
801 }
else if (
ModifierIs(Modifier, ModifierLen,
"s")) {
803 }
else if (
ModifierIs(Modifier, ModifierLen,
"plural")) {
806 }
else if (
ModifierIs(Modifier, ModifierLen,
"ordinal")) {
809 assert(ModifierLen == 0 &&
"Unknown integer modifier");
810 llvm::raw_svector_ostream(OutStr) << Val;
817 assert(ModifierLen == 0 &&
"No modifiers for token kinds yet");
819 llvm::raw_svector_ostream Out(OutStr);
822 Out <<
'\'' <<
S <<
'\'';
831 Out << '<' << S << '>
';
836 // ---- NAMES and TYPES ----
837 case DiagnosticsEngine::ak_identifierinfo: {
838 const IdentifierInfo *II = getArgIdentifier(ArgNo);
839 assert(ModifierLen == 0 && "No modifiers for strings yet");
841 // Don't crash
if get passed a null pointer by accident.
843 const char *S =
"(null)";
844 OutStr.append(S, S + strlen(S));
848 llvm::raw_svector_ostream(OutStr) <<
'\'' << II->getName() <<
'\'';
858 StringRef(Modifier, ModifierLen),
859 StringRef(Argument, ArgumentLen),
861 OutStr, QualTypeVals);
873 const char *ArgumentEnd = Argument + ArgumentLen;
874 const char *Pipe =
ScanFormat(Argument, ArgumentEnd,
'|');
878 if (
getDiags()->PrintTemplateTree && Tree.empty()) {
882 StringRef(Modifier, ModifierLen),
883 StringRef(Argument, ArgumentLen),
895 const char *FirstDollar =
ScanFormat(Argument, ArgumentEnd,
'$');
896 const char *SecondDollar =
ScanFormat(FirstDollar + 1, ArgumentEnd,
'$');
905 StringRef(Modifier, ModifierLen),
906 StringRef(Argument, ArgumentLen),
908 OutStr, QualTypeVals);
919 StringRef(Modifier, ModifierLen),
920 StringRef(Argument, ArgumentLen),
922 OutStr, QualTypeVals);
938 FormattedArgs.push_back(std::make_pair(Kind,
getRawArg(ArgNo)));
946 OutStr.append(Tree.begin(), Tree.end());
951 : ID(ID), Level(Level), Loc(), Message(Message) { }
955 :
ID(Info.getID()), Level(Level)
958 "Valid source location without setting a source manager for diagnostic");
963 this->Message.assign(Message.begin(), Message.end());
972 : ID(ID), Level(Level), Loc(Loc), Message(Message),
983 void IgnoringDiagConsumer::anchor() { }
1003 for (
unsigned I = 0;
I != NumCached; ++
I)
1004 FreeList[
I] = Cached +
I;
1005 NumFreeListEntries = NumCached;
1011 assert((NumFreeListEntries == NumCached ||
1012 llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1013 "A partial is on the lamb");
A diagnostic that indicates a problem or potential problem.
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)
ScanForward - Scans forward, looking for the given character, skipping nested clauses and escaped cha...
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.
Severity
Enum values that allow the client to map NOTEs, WARNINGs, and EXTENSIONs to either Ignore (nothing)...
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
A nullability kind paired with a bit indicating whether it used a context-sensitive keyword...
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
Whether values of this type can be null is (explicitly) unspecified.
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.
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
__INTPTR_TYPE__ intptr_t
A signed integer type with the property that any valid pointer to void can be converted to this type...
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...
detail::InMemoryDirectory::const_iterator I
bool EmitCurrentDiagnostic(bool Force=false)
Emit the current diagnostic and clear the diagnostic state.
A little helper class used to produce diagnostics.
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)
HandleOrdinalModifier - Handle the integer 'ord' modifier.
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.
const TemplateArgument * iterator
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.
OpenMPLinearClauseKind Modifier
Modifier of 'linear' clause.
static LLVM_READONLY bool isPunctuation(unsigned char c)
Return true if this character is an ASCII punctuation character.
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.
Flavor
Flavors of diagnostics we can emit.
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)
HandleSelectModifier - Handle the integer 'select' modifier.
range_iterator range_end() const
bool hasSourceManager() const
Level
The level of the diagnostic, after it has been through mapping.
StoredDiagnostic()=default
detail::InMemoryDirectory::const_iterator E
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)
HandlePluralModifier - Handle the integer 'plural' modifier.
unsigned Map[Count]
The type of a lookup table which maps from language-specific address spaces to target-specific ones...
Defines the Diagnostic-related interfaces.
static void HandleIntegerSModifier(unsigned ValNo, SmallVectorImpl< char > &OutStr)
HandleIntegerSModifier - Handle the integer 's' modifier.
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
A little helper class (which is basically a smart pointer that forwards info from DiagnosticsEngine) ...
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