#include "clang/Basic/CharInfo.h"
#include "clang/Basic/Diagnostic.h"
#include "clang/Basic/DiagnosticOptions.h"
#include "clang/Basic/IdentifierTable.h"
#include "clang/Basic/PartialDiagnostic.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Locale.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;
const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB,
DiagNullabilityKind nullability) {
StringRef string;
switch (nullability.first) {
case NullabilityKind::NonNull:
string = nullability.second ? "'nonnull'" : "'_Nonnull'";
break;
case NullabilityKind::Nullable:
string = nullability.second ? "'nullable'" : "'_Nullable'";
break;
case NullabilityKind::Unspecified:
string = nullability.second ? "'null_unspecified'" : "'_Null_unspecified'";
break;
}
DB.AddString(string);
return DB;
}
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) {
StringRef Str = "<can't format argument>";
Output.append(Str.begin(), Str.end());
}
DiagnosticsEngine::DiagnosticsEngine(
const IntrusiveRefCntPtr<DiagnosticIDs> &diags, DiagnosticOptions *DiagOpts,
DiagnosticConsumer *client, bool ShouldOwnClient)
: Diags(diags), DiagOpts(DiagOpts), Client(nullptr), SourceMgr(nullptr) {
setClient(client, ShouldOwnClient);
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = nullptr;
AllExtensionsSilenced = 0;
IgnoreAllWarnings = false;
WarningsAsErrors = false;
EnableAllWarnings = false;
ErrorsAsFatal = false;
FatalsAsError = false;
SuppressSystemWarnings = false;
SuppressAllDiagnostics = false;
ElideType = true;
PrintTemplateTree = false;
ShowColors = false;
ShowOverloads = Ovl_All;
ExtBehavior = diag::Severity::Ignored;
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
ConstexprBacktraceLimit = 0;
Reset();
}
DiagnosticsEngine::~DiagnosticsEngine() {
setClient(nullptr);
}
void DiagnosticsEngine::setClient(DiagnosticConsumer *client,
bool ShouldOwnClient) {
Owner.reset(ShouldOwnClient ? client : nullptr);
Client = client;
}
void DiagnosticsEngine::pushMappings(SourceLocation Loc) {
DiagStateOnPushStack.push_back(GetCurDiagState());
}
bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
if (DiagStateOnPushStack.empty())
return false;
if (DiagStateOnPushStack.back() != GetCurDiagState()) {
PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
}
DiagStateOnPushStack.pop_back();
return true;
}
void DiagnosticsEngine::Reset() {
ErrorOccurred = false;
UncompilableErrorOccurred = false;
FatalErrorOccurred = false;
UnrecoverableErrorOccurred = false;
NumWarnings = 0;
NumErrors = 0;
TrapNumErrorsOccurred = 0;
TrapNumUnrecoverableErrorsOccurred = 0;
CurDiagID = ~0U;
LastDiagLevel = DiagnosticIDs::Ignored;
DelayedDiagID = 0;
DiagStates.clear();
DiagStatePoints.clear();
DiagStateOnPushStack.clear();
DiagStates.emplace_back();
DiagStatePoints.push_back(DiagStatePoint(&DiagStates.back(), FullSourceLoc()));
}
void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
StringRef Arg2) {
if (DelayedDiagID)
return;
DelayedDiagID = DiagID;
DelayedDiagArg1 = Arg1.str();
DelayedDiagArg2 = Arg2.str();
}
void DiagnosticsEngine::ReportDelayed() {
Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
DelayedDiagID = 0;
DelayedDiagArg1.clear();
DelayedDiagArg2.clear();
}
DiagnosticsEngine::DiagStatePointsTy::iterator
DiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const {
assert(!DiagStatePoints.empty());
assert(DiagStatePoints.front().Loc.isInvalid() &&
"Should have created a DiagStatePoint for command-line");
if (!SourceMgr)
return DiagStatePoints.end() - 1;
FullSourceLoc Loc(L, *SourceMgr);
if (Loc.isInvalid())
return DiagStatePoints.end() - 1;
DiagStatePointsTy::iterator Pos = DiagStatePoints.end();
FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
if (LastStateChangePos.isValid() &&
Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
DiagStatePoint(nullptr, Loc));
--Pos;
return Pos;
}
void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
SourceLocation L) {
assert(Diag < diag::DIAG_UPPER_LIMIT &&
"Can only map builtin diagnostics");
assert((Diags->isBuiltinWarningOrExtension(Diag) ||
(Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
"Cannot map errors into warnings!");
assert(!DiagStatePoints.empty());
assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
FullSourceLoc Loc = SourceMgr? FullSourceLoc(L, *SourceMgr) : FullSourceLoc();
FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
if (Map == diag::Severity::Warning) {
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
if (Info.getSeverity() == diag::Severity::Error ||
Info.getSeverity() == diag::Severity::Fatal)
Map = Info.getSeverity();
}
DiagnosticMapping Mapping = makeUserMapping(Map, L);
if (Loc.isInvalid() || Loc == LastStateChangePos) {
GetCurDiagState()->setMapping(Diag, Mapping);
return;
}
if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
DiagStates.push_back(*GetCurDiagState());
PushDiagStatePoint(&DiagStates.back(), Loc);
GetCurDiagState()->setMapping(Diag, Mapping);
return;
}
DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
assert(Pos != DiagStatePoints.end());
for (DiagStatePointsTy::iterator
I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
I->State->setMapping(Diag, Mapping);
}
if (Pos->Loc == Loc) {
Pos->State->setMapping(Diag, Mapping);
return;
}
assert(Pos->Loc.isBeforeInTranslationUnitThan(Loc));
DiagStates.push_back(*Pos->State);
DiagState *NewState = &DiagStates.back();
NewState->setMapping(Diag, Mapping);
DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
FullSourceLoc(Loc, *SourceMgr)));
}
bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
StringRef Group, diag::Severity Map,
SourceLocation Loc) {
SmallVector<diag::kind, 256> GroupDiags;
if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
return true;
for (diag::kind Diag : GroupDiags)
setSeverity(Diag, Map, Loc);
return false;
}
bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
bool Enabled) {
if (Enabled)
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
diag::Severity::Error);
SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
GroupDiags))
return true;
for (diag::kind Diag : GroupDiags) {
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
if (Info.getSeverity() == diag::Severity::Error ||
Info.getSeverity() == diag::Severity::Fatal)
Info.setSeverity(diag::Severity::Warning);
Info.setNoWarningAsError(true);
}
return false;
}
bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
bool Enabled) {
if (Enabled)
return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
diag::Severity::Fatal);
SmallVector<diag::kind, 8> GroupDiags;
if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
GroupDiags))
return true;
for (diag::kind Diag : GroupDiags) {
DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
if (Info.getSeverity() == diag::Severity::Fatal)
Info.setSeverity(diag::Severity::Error);
Info.setNoErrorAsFatal(true);
}
return false;
}
void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
diag::Severity Map,
SourceLocation Loc) {
SmallVector<diag::kind, 64> AllDiags;
Diags->getAllDiagnostics(Flavor, AllDiags);
for (diag::kind Diag : AllDiags)
if (Diags->isBuiltinWarningOrExtension(Diag))
setSeverity(Diag, Map, Loc);
}
void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
CurDiagLoc = storedDiag.getLocation();
CurDiagID = storedDiag.getID();
NumDiagArgs = 0;
DiagRanges.clear();
DiagRanges.append(storedDiag.range_begin(), storedDiag.range_end());
DiagFixItHints.clear();
DiagFixItHints.append(storedDiag.fixit_begin(), storedDiag.fixit_end());
assert(Client && "DiagnosticConsumer not set!");
Level DiagLevel = storedDiag.getLevel();
Diagnostic Info(this, storedDiag.getMessage());
Client->HandleDiagnostic(DiagLevel, Info);
if (Client->IncludeInDiagnosticCounts()) {
if (DiagLevel == DiagnosticsEngine::Warning)
++NumWarnings;
}
CurDiagID = ~0U;
}
bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) {
assert(getClient() && "DiagnosticClient not set!");
bool Emitted;
if (Force) {
Diagnostic Info(this);
DiagnosticIDs::Level DiagLevel
= Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this);
Emitted = (DiagLevel != DiagnosticIDs::Ignored);
if (Emitted) {
Diags->EmitDiag(*this, DiagLevel);
}
} else {
Emitted = ProcessDiag();
}
unsigned DiagID = CurDiagID;
Clear();
if (!Force && DelayedDiagID && DelayedDiagID != DiagID)
ReportDelayed();
return Emitted;
}
DiagnosticConsumer::~DiagnosticConsumer() {}
void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
if (!IncludeInDiagnosticCounts())
return;
if (DiagLevel == DiagnosticsEngine::Warning)
++NumWarnings;
else if (DiagLevel >= DiagnosticsEngine::Error)
++NumErrors;
}
template <std::size_t StrLen>
static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
const char (&Str)[StrLen]) {
return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
}
static const char *ScanFormat(const char *I, const char *E, char Target) {
unsigned Depth = 0;
for ( ; I != E; ++I) {
if (Depth == 0 && *I == Target) return I;
if (Depth != 0 && *I == '}') Depth--;
if (*I == '%') {
I++;
if (I == E) break;
if (!isDigit(*I) && !isPunctuation(*I)) {
for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
if (I == E) break;
if (*I == '{')
Depth++;
}
}
}
return E;
}
static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
const char *Argument, unsigned ArgumentLen,
SmallVectorImpl<char> &OutStr) {
const char *ArgumentEnd = Argument+ArgumentLen;
while (ValNo) {
const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
" larger than the number of options in the diagnostic string!");
Argument = NextVal+1; --ValNo;
}
const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
}
static void HandleIntegerSModifier(unsigned ValNo,
SmallVectorImpl<char> &OutStr) {
if (ValNo != 1)
OutStr.push_back('s');
}
static void HandleOrdinalModifier(unsigned ValNo,
SmallVectorImpl<char> &OutStr) {
assert(ValNo != 0 && "ValNo must be strictly positive!");
llvm::raw_svector_ostream Out(OutStr);
Out << ValNo << llvm::getOrdinalSuffix(ValNo);
}
static unsigned PluralNumber(const char *&Start, const char *End) {
unsigned Val = 0;
while (Start != End && *Start >= '0' && *Start <= '9') {
Val *= 10;
Val += *Start - '0';
++Start;
}
return Val;
}
static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
if (*Start != '[') {
unsigned Ref = PluralNumber(Start, End);
return Ref == Val;
}
++Start;
unsigned Low = PluralNumber(Start, End);
assert(*Start == ',' && "Bad plural expression syntax: expected ,");
++Start;
unsigned High = PluralNumber(Start, End);
assert(*Start == ']' && "Bad plural expression syntax: expected )");
++Start;
return Low <= Val && Val <= High;
}
static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
if (*Start == ':')
return true;
while (1) {
char C = *Start;
if (C == '%') {
++Start;
unsigned Arg = PluralNumber(Start, End);
assert(*Start == '=' && "Bad plural expression syntax: expected =");
++Start;
unsigned ValMod = ValNo % Arg;
if (TestPluralRange(ValMod, Start, End))
return true;
} else {
assert((C == '[' || (C >= '0' && C <= '9')) &&
"Bad plural expression syntax: unexpected character");
if (TestPluralRange(ValNo, Start, End))
return true;
}
Start = std::find(Start, End, ',');
if (Start == End)
break;
++Start;
}
return false;
}
static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
const char *Argument, unsigned ArgumentLen,
SmallVectorImpl<char> &OutStr) {
const char *ArgumentEnd = Argument + ArgumentLen;
while (1) {
assert(Argument < ArgumentEnd && "Plural expression didn't match.");
const char *ExprEnd = Argument;
while (*ExprEnd != ':') {
assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
++ExprEnd;
}
if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
Argument = ExprEnd + 1;
ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
return;
}
Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
}
}
static const char *getTokenDescForDiagnostic(tok::TokenKind Kind) {
switch (Kind) {
case tok::identifier:
return "identifier";
default:
return nullptr;
}
}
void Diagnostic::
FormatDiagnostic(SmallVectorImpl<char> &OutStr) const {
if (!StoredDiagMessage.empty()) {
OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
return;
}
StringRef Diag =
getDiags()->getDiagnosticIDs()->getDescription(getID());
FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
}
void Diagnostic::
FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
SmallVectorImpl<char> &OutStr) const {
if (DiagEnd - DiagStr == 2 &&
StringRef(DiagStr, DiagEnd - DiagStr).equals("%0") &&
getArgKind(0) == DiagnosticsEngine::ak_std_string) {
const std::string &S = getArgStdStr(0);
for (char c : S) {
if (llvm::sys::locale::isPrint(c) || c == '\t') {
OutStr.push_back(c);
}
}
return;
}
SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs;
SmallVector<intptr_t, 2> QualTypeVals;
SmallVector<char, 64> Tree;
for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
if (getArgKind(i) == DiagnosticsEngine::ak_qualtype)
QualTypeVals.push_back(getRawArg(i));
while (DiagStr != DiagEnd) {
if (DiagStr[0] != '%') {
const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
OutStr.append(DiagStr, StrEnd);
DiagStr = StrEnd;
continue;
} else if (isPunctuation(DiagStr[1])) {
OutStr.push_back(DiagStr[1]); DiagStr += 2;
continue;
}
++DiagStr;
const char *Modifier = nullptr, *Argument = nullptr;
unsigned ModifierLen = 0, ArgumentLen = 0;
if (!isDigit(DiagStr[0])) {
Modifier = DiagStr;
while (DiagStr[0] == '-' ||
(DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
++DiagStr;
ModifierLen = DiagStr-Modifier;
if (DiagStr[0] == '{') {
++DiagStr; Argument = DiagStr;
DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
ArgumentLen = DiagStr-Argument;
++DiagStr; }
}
assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
unsigned ArgNo = *DiagStr++ - '0';
unsigned ArgNo2 = ArgNo;
DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "diff")) {
assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
"Invalid format for diff modifier");
++DiagStr; ArgNo2 = *DiagStr++ - '0';
DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2);
if (Kind == DiagnosticsEngine::ak_qualtype &&
Kind2 == DiagnosticsEngine::ak_qualtype)
Kind = DiagnosticsEngine::ak_qualtype_pair;
else {
const char *Pipe = ScanFormat(Argument, Argument + ArgumentLen, '|');
const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
FormatDiagnostic(Argument, FirstDollar, OutStr);
FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
continue;
}
}
switch (Kind) {
case DiagnosticsEngine::ak_std_string: {
const std::string &S = getArgStdStr(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
OutStr.append(S.begin(), S.end());
break;
}
case DiagnosticsEngine::ak_c_string: {
const char *S = getArgCStr(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
if (!S)
S = "(null)";
OutStr.append(S, S + strlen(S));
break;
}
case DiagnosticsEngine::ak_sint: {
int Val = getArgSInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
HandleOrdinalModifier((unsigned)Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
llvm::raw_svector_ostream(OutStr) << Val;
}
break;
}
case DiagnosticsEngine::ak_uint: {
unsigned Val = getArgUInt(ArgNo);
if (ModifierIs(Modifier, ModifierLen, "select")) {
HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "s")) {
HandleIntegerSModifier(Val, OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "plural")) {
HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
OutStr);
} else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
HandleOrdinalModifier(Val, OutStr);
} else {
assert(ModifierLen == 0 && "Unknown integer modifier");
llvm::raw_svector_ostream(OutStr) << Val;
}
break;
}
case DiagnosticsEngine::ak_tokenkind: {
tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
assert(ModifierLen == 0 && "No modifiers for token kinds yet");
llvm::raw_svector_ostream Out(OutStr);
if (const char *S = tok::getPunctuatorSpelling(Kind))
Out << '\'' << S << '\'';
else if (const char *S = tok::getKeywordSpelling(Kind))
Out << S;
else if (const char *S = getTokenDescForDiagnostic(Kind))
Out << S;
else if (const char *S = tok::getTokenName(Kind))
Out << '<' << S << '>';
else
Out << "(null)";
break;
}
case DiagnosticsEngine::ak_identifierinfo: {
const IdentifierInfo *II = getArgIdentifier(ArgNo);
assert(ModifierLen == 0 && "No modifiers for strings yet");
if (!II) {
const char *S = "(null)";
OutStr.append(S, S + strlen(S));
continue;
}
llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
break;
}
case DiagnosticsEngine::ak_qualtype:
case DiagnosticsEngine::ak_declarationname:
case DiagnosticsEngine::ak_nameddecl:
case DiagnosticsEngine::ak_nestednamespec:
case DiagnosticsEngine::ak_declcontext:
case DiagnosticsEngine::ak_attr:
getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
StringRef(Modifier, ModifierLen),
StringRef(Argument, ArgumentLen),
FormattedArgs,
OutStr, QualTypeVals);
break;
case DiagnosticsEngine::ak_qualtype_pair:
TemplateDiffTypes TDT;
TDT.FromType = getRawArg(ArgNo);
TDT.ToType = getRawArg(ArgNo2);
TDT.ElideType = getDiags()->ElideType;
TDT.ShowColors = getDiags()->ShowColors;
TDT.TemplateDiffUsed = false;
intptr_t val = reinterpret_cast<intptr_t>(&TDT);
const char *ArgumentEnd = Argument + ArgumentLen;
const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
if (getDiags()->PrintTemplateTree && Tree.empty()) {
TDT.PrintFromType = true;
TDT.PrintTree = true;
getDiags()->ConvertArgToString(Kind, val,
StringRef(Modifier, ModifierLen),
StringRef(Argument, ArgumentLen),
FormattedArgs,
Tree, QualTypeVals);
if (!Tree.empty()) {
FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
break;
}
}
const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
FormatDiagnostic(Argument, FirstDollar, OutStr);
TDT.PrintTree = false;
TDT.PrintFromType = true;
getDiags()->ConvertArgToString(Kind, val,
StringRef(Modifier, ModifierLen),
StringRef(Argument, ArgumentLen),
FormattedArgs,
OutStr, QualTypeVals);
if (!TDT.TemplateDiffUsed)
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
TDT.FromType));
FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
TDT.PrintFromType = false;
getDiags()->ConvertArgToString(Kind, val,
StringRef(Modifier, ModifierLen),
StringRef(Argument, ArgumentLen),
FormattedArgs,
OutStr, QualTypeVals);
if (!TDT.TemplateDiffUsed)
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
TDT.ToType));
FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
break;
}
if (Kind == DiagnosticsEngine::ak_qualtype_pair)
continue;
else if (Kind != DiagnosticsEngine::ak_std_string)
FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
else
FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,
(intptr_t)getArgStdStr(ArgNo).c_str()));
}
OutStr.append(Tree.begin(), Tree.end());
}
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
StringRef Message)
: ID(ID), Level(Level), Loc(), Message(Message) { }
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
const Diagnostic &Info)
: ID(Info.getID()), Level(Level)
{
assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
"Valid source location without setting a source manager for diagnostic");
if (Info.getLocation().isValid())
Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
SmallString<64> Message;
Info.FormatDiagnostic(Message);
this->Message.assign(Message.begin(), Message.end());
this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
}
StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
StringRef Message, FullSourceLoc Loc,
ArrayRef<CharSourceRange> Ranges,
ArrayRef<FixItHint> FixIts)
: ID(ID), Level(Level), Loc(Loc), Message(Message),
Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
{
}
bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
void IgnoringDiagConsumer::anchor() { }
ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() {}
void ForwardingDiagnosticConsumer::HandleDiagnostic(
DiagnosticsEngine::Level DiagLevel,
const Diagnostic &Info) {
Target.HandleDiagnostic(DiagLevel, Info);
}
void ForwardingDiagnosticConsumer::clear() {
DiagnosticConsumer::clear();
Target.clear();
}
bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
return Target.IncludeInDiagnosticCounts();
}
PartialDiagnostic::StorageAllocator::StorageAllocator() {
for (unsigned I = 0; I != NumCached; ++I)
FreeList[I] = Cached + I;
NumFreeListEntries = NumCached;
}
PartialDiagnostic::StorageAllocator::~StorageAllocator() {
assert((NumFreeListEntries == NumCached ||
llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
"A partial is on the lamb");
}