//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file implements the Diagnostic-related interfaces.
//
//===----------------------------------------------------------------------===//
#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/raw_ostream.h"
using namespace clang;
static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
const char *Modifier, unsigned ML,
const char *Argument, unsigned ArgLen,
const DiagnosticsEngine::ArgumentValue *PrevArgs,
unsigned NumPrevArgs,
SmallVectorImpl<char> &Output,
void *Cookie,
ArrayRef<intptr_t> QualTypeVals) {
const char *Str = "<can't format argument>";
Output.append(Str, Str+strlen(Str));
}
DiagnosticsEngine::DiagnosticsEngine(
const IntrusiveRefCntPtr<DiagnosticIDs> &diags,
DiagnosticOptions *DiagOpts,
DiagnosticConsumer *client, bool ShouldOwnClient)
: Diags(diags), DiagOpts(DiagOpts), Client(client),
OwnsDiagClient(ShouldOwnClient), SourceMgr(0) {
ArgToStringFn = DummyArgToStringFn;
ArgToStringCookie = 0;
AllExtensionsSilenced = 0;
IgnoreAllWarnings = false;
WarningsAsErrors = false;
EnableAllWarnings = false;
ErrorsAsFatal = false;
SuppressSystemWarnings = false;
SuppressAllDiagnostics = false;
ElideType = true;
PrintTemplateTree = false;
ShowColors = false;
ShowOverloads = Ovl_All;
ExtBehavior = Ext_Ignore;
ErrorLimit = 0;
TemplateBacktraceLimit = 0;
ConstexprBacktraceLimit = 0;
Reset();
}
DiagnosticsEngine::~DiagnosticsEngine() {
if (OwnsDiagClient)
delete Client;
}
void DiagnosticsEngine::setClient(DiagnosticConsumer *client,
bool ShouldOwnClient) {
if (OwnsDiagClient && Client)
delete Client;
Client = client;
OwnsDiagClient = ShouldOwnClient;
}
void DiagnosticsEngine::pushMappings(SourceLocation Loc) {
DiagStateOnPushStack.push_back(GetCurDiagState());
}
bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
if (DiagStateOnPushStack.empty())
return false;
if (DiagStateOnPushStack.back() != GetCurDiagState()) {
// State changed at some point between push/pop.
PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
}
DiagStateOnPushStack.pop_back();
return true;
}
void DiagnosticsEngine::Reset() {
ErrorOccurred = false;
UncompilableErrorOccurred = false;
FatalErrorOccurred = false;
UnrecoverableErrorOccurred = false;
NumWarnings = 0;
NumErrors = 0;
NumErrorsSuppressed = 0;
TrapNumErrorsOccurred = 0;
TrapNumUnrecoverableErrorsOccurred = 0;
CurDiagID = ~0U;
LastDiagLevel = DiagnosticIDs::Ignored;
DelayedDiagID = 0;
// Clear state related to #pragma diagnostic.
DiagStates.clear();
DiagStatePoints.clear();
DiagStateOnPushStack.clear();
// Create a DiagState and DiagStatePoint representing diagnostic changes
// through command-line.
DiagStates.push_back(DiagState());
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.