17330f729Sjoerg //===- Diagnostic.cpp - C Language Family Diagnostic Handling -------------===//
27330f729Sjoerg //
37330f729Sjoerg // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
47330f729Sjoerg // See https://llvm.org/LICENSE.txt for license information.
57330f729Sjoerg // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
67330f729Sjoerg //
77330f729Sjoerg //===----------------------------------------------------------------------===//
87330f729Sjoerg //
97330f729Sjoerg // This file implements the Diagnostic-related interfaces.
107330f729Sjoerg //
117330f729Sjoerg //===----------------------------------------------------------------------===//
127330f729Sjoerg
137330f729Sjoerg #include "clang/Basic/Diagnostic.h"
147330f729Sjoerg #include "clang/Basic/CharInfo.h"
157330f729Sjoerg #include "clang/Basic/DiagnosticError.h"
167330f729Sjoerg #include "clang/Basic/DiagnosticIDs.h"
177330f729Sjoerg #include "clang/Basic/DiagnosticOptions.h"
187330f729Sjoerg #include "clang/Basic/IdentifierTable.h"
197330f729Sjoerg #include "clang/Basic/PartialDiagnostic.h"
207330f729Sjoerg #include "clang/Basic/SourceLocation.h"
217330f729Sjoerg #include "clang/Basic/SourceManager.h"
227330f729Sjoerg #include "clang/Basic/Specifiers.h"
237330f729Sjoerg #include "clang/Basic/TokenKinds.h"
247330f729Sjoerg #include "llvm/ADT/SmallString.h"
257330f729Sjoerg #include "llvm/ADT/SmallVector.h"
267330f729Sjoerg #include "llvm/ADT/StringExtras.h"
277330f729Sjoerg #include "llvm/ADT/StringRef.h"
287330f729Sjoerg #include "llvm/Support/CrashRecoveryContext.h"
297330f729Sjoerg #include "llvm/Support/Locale.h"
307330f729Sjoerg #include "llvm/Support/raw_ostream.h"
317330f729Sjoerg #include <algorithm>
327330f729Sjoerg #include <cassert>
337330f729Sjoerg #include <cstddef>
347330f729Sjoerg #include <cstdint>
357330f729Sjoerg #include <cstring>
367330f729Sjoerg #include <limits>
377330f729Sjoerg #include <string>
387330f729Sjoerg #include <utility>
397330f729Sjoerg #include <vector>
407330f729Sjoerg
417330f729Sjoerg using namespace clang;
427330f729Sjoerg
operator <<(const StreamingDiagnostic & DB,DiagNullabilityKind nullability)43*e038c9c4Sjoerg const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
447330f729Sjoerg DiagNullabilityKind nullability) {
457330f729Sjoerg StringRef string;
467330f729Sjoerg switch (nullability.first) {
477330f729Sjoerg case NullabilityKind::NonNull:
487330f729Sjoerg string = nullability.second ? "'nonnull'" : "'_Nonnull'";
497330f729Sjoerg break;
507330f729Sjoerg
517330f729Sjoerg case NullabilityKind::Nullable:
527330f729Sjoerg string = nullability.second ? "'nullable'" : "'_Nullable'";
537330f729Sjoerg break;
547330f729Sjoerg
557330f729Sjoerg case NullabilityKind::Unspecified:
567330f729Sjoerg string = nullability.second ? "'null_unspecified'" : "'_Null_unspecified'";
577330f729Sjoerg break;
58*e038c9c4Sjoerg
59*e038c9c4Sjoerg case NullabilityKind::NullableResult:
60*e038c9c4Sjoerg assert(!nullability.second &&
61*e038c9c4Sjoerg "_Nullable_result isn't supported as context-sensitive keyword");
62*e038c9c4Sjoerg string = "_Nullable_result";
63*e038c9c4Sjoerg break;
647330f729Sjoerg }
657330f729Sjoerg
667330f729Sjoerg DB.AddString(string);
677330f729Sjoerg return DB;
687330f729Sjoerg }
697330f729Sjoerg
operator <<(const StreamingDiagnostic & DB,llvm::Error && E)70*e038c9c4Sjoerg const StreamingDiagnostic &clang::operator<<(const StreamingDiagnostic &DB,
71*e038c9c4Sjoerg llvm::Error &&E) {
72*e038c9c4Sjoerg DB.AddString(toString(std::move(E)));
73*e038c9c4Sjoerg return DB;
74*e038c9c4Sjoerg }
75*e038c9c4Sjoerg
DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK,intptr_t QT,StringRef Modifier,StringRef Argument,ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,SmallVectorImpl<char> & Output,void * Cookie,ArrayRef<intptr_t> QualTypeVals)767330f729Sjoerg static void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
777330f729Sjoerg StringRef Modifier, StringRef Argument,
787330f729Sjoerg ArrayRef<DiagnosticsEngine::ArgumentValue> PrevArgs,
797330f729Sjoerg SmallVectorImpl<char> &Output,
807330f729Sjoerg void *Cookie,
817330f729Sjoerg ArrayRef<intptr_t> QualTypeVals) {
827330f729Sjoerg StringRef Str = "<can't format argument>";
837330f729Sjoerg Output.append(Str.begin(), Str.end());
847330f729Sjoerg }
857330f729Sjoerg
DiagnosticsEngine(IntrusiveRefCntPtr<DiagnosticIDs> diags,IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts,DiagnosticConsumer * client,bool ShouldOwnClient)867330f729Sjoerg DiagnosticsEngine::DiagnosticsEngine(
877330f729Sjoerg IntrusiveRefCntPtr<DiagnosticIDs> diags,
887330f729Sjoerg IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts, DiagnosticConsumer *client,
897330f729Sjoerg bool ShouldOwnClient)
907330f729Sjoerg : Diags(std::move(diags)), DiagOpts(std::move(DiagOpts)) {
917330f729Sjoerg setClient(client, ShouldOwnClient);
927330f729Sjoerg ArgToStringFn = DummyArgToStringFn;
937330f729Sjoerg
947330f729Sjoerg Reset();
957330f729Sjoerg }
967330f729Sjoerg
~DiagnosticsEngine()977330f729Sjoerg DiagnosticsEngine::~DiagnosticsEngine() {
987330f729Sjoerg // If we own the diagnostic client, destroy it first so that it can access the
997330f729Sjoerg // engine from its destructor.
1007330f729Sjoerg setClient(nullptr);
1017330f729Sjoerg }
1027330f729Sjoerg
dump() const1037330f729Sjoerg void DiagnosticsEngine::dump() const {
1047330f729Sjoerg DiagStatesByLoc.dump(*SourceMgr);
1057330f729Sjoerg }
1067330f729Sjoerg
dump(StringRef DiagName) const1077330f729Sjoerg void DiagnosticsEngine::dump(StringRef DiagName) const {
1087330f729Sjoerg DiagStatesByLoc.dump(*SourceMgr, DiagName);
1097330f729Sjoerg }
1107330f729Sjoerg
setClient(DiagnosticConsumer * client,bool ShouldOwnClient)1117330f729Sjoerg void DiagnosticsEngine::setClient(DiagnosticConsumer *client,
1127330f729Sjoerg bool ShouldOwnClient) {
1137330f729Sjoerg Owner.reset(ShouldOwnClient ? client : nullptr);
1147330f729Sjoerg Client = client;
1157330f729Sjoerg }
1167330f729Sjoerg
pushMappings(SourceLocation Loc)1177330f729Sjoerg void DiagnosticsEngine::pushMappings(SourceLocation Loc) {
1187330f729Sjoerg DiagStateOnPushStack.push_back(GetCurDiagState());
1197330f729Sjoerg }
1207330f729Sjoerg
popMappings(SourceLocation Loc)1217330f729Sjoerg bool DiagnosticsEngine::popMappings(SourceLocation Loc) {
1227330f729Sjoerg if (DiagStateOnPushStack.empty())
1237330f729Sjoerg return false;
1247330f729Sjoerg
1257330f729Sjoerg if (DiagStateOnPushStack.back() != GetCurDiagState()) {
1267330f729Sjoerg // State changed at some point between push/pop.
1277330f729Sjoerg PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
1287330f729Sjoerg }
1297330f729Sjoerg DiagStateOnPushStack.pop_back();
1307330f729Sjoerg return true;
1317330f729Sjoerg }
1327330f729Sjoerg
Reset()1337330f729Sjoerg void DiagnosticsEngine::Reset() {
1347330f729Sjoerg ErrorOccurred = false;
1357330f729Sjoerg UncompilableErrorOccurred = false;
1367330f729Sjoerg FatalErrorOccurred = false;
1377330f729Sjoerg UnrecoverableErrorOccurred = false;
1387330f729Sjoerg
1397330f729Sjoerg NumWarnings = 0;
1407330f729Sjoerg NumErrors = 0;
1417330f729Sjoerg TrapNumErrorsOccurred = 0;
1427330f729Sjoerg TrapNumUnrecoverableErrorsOccurred = 0;
1437330f729Sjoerg
1447330f729Sjoerg CurDiagID = std::numeric_limits<unsigned>::max();
1457330f729Sjoerg LastDiagLevel = DiagnosticIDs::Ignored;
1467330f729Sjoerg DelayedDiagID = 0;
1477330f729Sjoerg
1487330f729Sjoerg // Clear state related to #pragma diagnostic.
1497330f729Sjoerg DiagStates.clear();
1507330f729Sjoerg DiagStatesByLoc.clear();
1517330f729Sjoerg DiagStateOnPushStack.clear();
1527330f729Sjoerg
1537330f729Sjoerg // Create a DiagState and DiagStatePoint representing diagnostic changes
1547330f729Sjoerg // through command-line.
1557330f729Sjoerg DiagStates.emplace_back();
1567330f729Sjoerg DiagStatesByLoc.appendFirst(&DiagStates.back());
1577330f729Sjoerg }
1587330f729Sjoerg
SetDelayedDiagnostic(unsigned DiagID,StringRef Arg1,StringRef Arg2,StringRef Arg3)1597330f729Sjoerg void DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
160*e038c9c4Sjoerg StringRef Arg2, StringRef Arg3) {
1617330f729Sjoerg if (DelayedDiagID)
1627330f729Sjoerg return;
1637330f729Sjoerg
1647330f729Sjoerg DelayedDiagID = DiagID;
1657330f729Sjoerg DelayedDiagArg1 = Arg1.str();
1667330f729Sjoerg DelayedDiagArg2 = Arg2.str();
167*e038c9c4Sjoerg DelayedDiagArg3 = Arg3.str();
1687330f729Sjoerg }
1697330f729Sjoerg
ReportDelayed()1707330f729Sjoerg void DiagnosticsEngine::ReportDelayed() {
1717330f729Sjoerg unsigned ID = DelayedDiagID;
1727330f729Sjoerg DelayedDiagID = 0;
173*e038c9c4Sjoerg Report(ID) << DelayedDiagArg1 << DelayedDiagArg2 << DelayedDiagArg3;
1747330f729Sjoerg }
1757330f729Sjoerg
appendFirst(DiagState * State)1767330f729Sjoerg void DiagnosticsEngine::DiagStateMap::appendFirst(DiagState *State) {
1777330f729Sjoerg assert(Files.empty() && "not first");
1787330f729Sjoerg FirstDiagState = CurDiagState = State;
1797330f729Sjoerg CurDiagStateLoc = SourceLocation();
1807330f729Sjoerg }
1817330f729Sjoerg
append(SourceManager & SrcMgr,SourceLocation Loc,DiagState * State)1827330f729Sjoerg void DiagnosticsEngine::DiagStateMap::append(SourceManager &SrcMgr,
1837330f729Sjoerg SourceLocation Loc,
1847330f729Sjoerg DiagState *State) {
1857330f729Sjoerg CurDiagState = State;
1867330f729Sjoerg CurDiagStateLoc = Loc;
1877330f729Sjoerg
1887330f729Sjoerg std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
1897330f729Sjoerg unsigned Offset = Decomp.second;
1907330f729Sjoerg for (File *F = getFile(SrcMgr, Decomp.first); F;
1917330f729Sjoerg Offset = F->ParentOffset, F = F->Parent) {
1927330f729Sjoerg F->HasLocalTransitions = true;
1937330f729Sjoerg auto &Last = F->StateTransitions.back();
1947330f729Sjoerg assert(Last.Offset <= Offset && "state transitions added out of order");
1957330f729Sjoerg
1967330f729Sjoerg if (Last.Offset == Offset) {
1977330f729Sjoerg if (Last.State == State)
1987330f729Sjoerg break;
1997330f729Sjoerg Last.State = State;
2007330f729Sjoerg continue;
2017330f729Sjoerg }
2027330f729Sjoerg
2037330f729Sjoerg F->StateTransitions.push_back({State, Offset});
2047330f729Sjoerg }
2057330f729Sjoerg }
2067330f729Sjoerg
2077330f729Sjoerg DiagnosticsEngine::DiagState *
lookup(SourceManager & SrcMgr,SourceLocation Loc) const2087330f729Sjoerg DiagnosticsEngine::DiagStateMap::lookup(SourceManager &SrcMgr,
2097330f729Sjoerg SourceLocation Loc) const {
2107330f729Sjoerg // Common case: we have not seen any diagnostic pragmas.
2117330f729Sjoerg if (Files.empty())
2127330f729Sjoerg return FirstDiagState;
2137330f729Sjoerg
2147330f729Sjoerg std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedLoc(Loc);
2157330f729Sjoerg const File *F = getFile(SrcMgr, Decomp.first);
2167330f729Sjoerg return F->lookup(Decomp.second);
2177330f729Sjoerg }
2187330f729Sjoerg
2197330f729Sjoerg DiagnosticsEngine::DiagState *
lookup(unsigned Offset) const2207330f729Sjoerg DiagnosticsEngine::DiagStateMap::File::lookup(unsigned Offset) const {
2217330f729Sjoerg auto OnePastIt =
2227330f729Sjoerg llvm::partition_point(StateTransitions, [=](const DiagStatePoint &P) {
2237330f729Sjoerg return P.Offset <= Offset;
2247330f729Sjoerg });
2257330f729Sjoerg assert(OnePastIt != StateTransitions.begin() && "missing initial state");
2267330f729Sjoerg return OnePastIt[-1].State;
2277330f729Sjoerg }
2287330f729Sjoerg
2297330f729Sjoerg DiagnosticsEngine::DiagStateMap::File *
getFile(SourceManager & SrcMgr,FileID ID) const2307330f729Sjoerg DiagnosticsEngine::DiagStateMap::getFile(SourceManager &SrcMgr,
2317330f729Sjoerg FileID ID) const {
2327330f729Sjoerg // Get or insert the File for this ID.
2337330f729Sjoerg auto Range = Files.equal_range(ID);
2347330f729Sjoerg if (Range.first != Range.second)
2357330f729Sjoerg return &Range.first->second;
2367330f729Sjoerg auto &F = Files.insert(Range.first, std::make_pair(ID, File()))->second;
2377330f729Sjoerg
2387330f729Sjoerg // We created a new File; look up the diagnostic state at the start of it and
2397330f729Sjoerg // initialize it.
2407330f729Sjoerg if (ID.isValid()) {
2417330f729Sjoerg std::pair<FileID, unsigned> Decomp = SrcMgr.getDecomposedIncludedLoc(ID);
2427330f729Sjoerg F.Parent = getFile(SrcMgr, Decomp.first);
2437330f729Sjoerg F.ParentOffset = Decomp.second;
2447330f729Sjoerg F.StateTransitions.push_back({F.Parent->lookup(Decomp.second), 0});
2457330f729Sjoerg } else {
2467330f729Sjoerg // This is the (imaginary) root file into which we pretend all top-level
2477330f729Sjoerg // files are included; it descends from the initial state.
2487330f729Sjoerg //
2497330f729Sjoerg // FIXME: This doesn't guarantee that we use the same ordering as
2507330f729Sjoerg // isBeforeInTranslationUnit in the cases where someone invented another
2517330f729Sjoerg // top-level file and added diagnostic pragmas to it. See the code at the
2527330f729Sjoerg // end of isBeforeInTranslationUnit for the quirks it deals with.
2537330f729Sjoerg F.StateTransitions.push_back({FirstDiagState, 0});
2547330f729Sjoerg }
2557330f729Sjoerg return &F;
2567330f729Sjoerg }
2577330f729Sjoerg
dump(SourceManager & SrcMgr,StringRef DiagName) const2587330f729Sjoerg void DiagnosticsEngine::DiagStateMap::dump(SourceManager &SrcMgr,
2597330f729Sjoerg StringRef DiagName) const {
2607330f729Sjoerg llvm::errs() << "diagnostic state at ";
2617330f729Sjoerg CurDiagStateLoc.print(llvm::errs(), SrcMgr);
2627330f729Sjoerg llvm::errs() << ": " << CurDiagState << "\n";
2637330f729Sjoerg
2647330f729Sjoerg for (auto &F : Files) {
2657330f729Sjoerg FileID ID = F.first;
2667330f729Sjoerg File &File = F.second;
2677330f729Sjoerg
2687330f729Sjoerg bool PrintedOuterHeading = false;
2697330f729Sjoerg auto PrintOuterHeading = [&] {
2707330f729Sjoerg if (PrintedOuterHeading) return;
2717330f729Sjoerg PrintedOuterHeading = true;
2727330f729Sjoerg
2737330f729Sjoerg llvm::errs() << "File " << &File << " <FileID " << ID.getHashValue()
274*e038c9c4Sjoerg << ">: " << SrcMgr.getBufferOrFake(ID).getBufferIdentifier();
275*e038c9c4Sjoerg
2767330f729Sjoerg if (F.second.Parent) {
2777330f729Sjoerg std::pair<FileID, unsigned> Decomp =
2787330f729Sjoerg SrcMgr.getDecomposedIncludedLoc(ID);
2797330f729Sjoerg assert(File.ParentOffset == Decomp.second);
2807330f729Sjoerg llvm::errs() << " parent " << File.Parent << " <FileID "
2817330f729Sjoerg << Decomp.first.getHashValue() << "> ";
2827330f729Sjoerg SrcMgr.getLocForStartOfFile(Decomp.first)
2837330f729Sjoerg .getLocWithOffset(Decomp.second)
2847330f729Sjoerg .print(llvm::errs(), SrcMgr);
2857330f729Sjoerg }
2867330f729Sjoerg if (File.HasLocalTransitions)
2877330f729Sjoerg llvm::errs() << " has_local_transitions";
2887330f729Sjoerg llvm::errs() << "\n";
2897330f729Sjoerg };
2907330f729Sjoerg
2917330f729Sjoerg if (DiagName.empty())
2927330f729Sjoerg PrintOuterHeading();
2937330f729Sjoerg
2947330f729Sjoerg for (DiagStatePoint &Transition : File.StateTransitions) {
2957330f729Sjoerg bool PrintedInnerHeading = false;
2967330f729Sjoerg auto PrintInnerHeading = [&] {
2977330f729Sjoerg if (PrintedInnerHeading) return;
2987330f729Sjoerg PrintedInnerHeading = true;
2997330f729Sjoerg
3007330f729Sjoerg PrintOuterHeading();
3017330f729Sjoerg llvm::errs() << " ";
3027330f729Sjoerg SrcMgr.getLocForStartOfFile(ID)
3037330f729Sjoerg .getLocWithOffset(Transition.Offset)
3047330f729Sjoerg .print(llvm::errs(), SrcMgr);
3057330f729Sjoerg llvm::errs() << ": state " << Transition.State << ":\n";
3067330f729Sjoerg };
3077330f729Sjoerg
3087330f729Sjoerg if (DiagName.empty())
3097330f729Sjoerg PrintInnerHeading();
3107330f729Sjoerg
3117330f729Sjoerg for (auto &Mapping : *Transition.State) {
3127330f729Sjoerg StringRef Option =
3137330f729Sjoerg DiagnosticIDs::getWarningOptionForDiag(Mapping.first);
3147330f729Sjoerg if (!DiagName.empty() && DiagName != Option)
3157330f729Sjoerg continue;
3167330f729Sjoerg
3177330f729Sjoerg PrintInnerHeading();
3187330f729Sjoerg llvm::errs() << " ";
3197330f729Sjoerg if (Option.empty())
3207330f729Sjoerg llvm::errs() << "<unknown " << Mapping.first << ">";
3217330f729Sjoerg else
3227330f729Sjoerg llvm::errs() << Option;
3237330f729Sjoerg llvm::errs() << ": ";
3247330f729Sjoerg
3257330f729Sjoerg switch (Mapping.second.getSeverity()) {
3267330f729Sjoerg case diag::Severity::Ignored: llvm::errs() << "ignored"; break;
3277330f729Sjoerg case diag::Severity::Remark: llvm::errs() << "remark"; break;
3287330f729Sjoerg case diag::Severity::Warning: llvm::errs() << "warning"; break;
3297330f729Sjoerg case diag::Severity::Error: llvm::errs() << "error"; break;
3307330f729Sjoerg case diag::Severity::Fatal: llvm::errs() << "fatal"; break;
3317330f729Sjoerg }
3327330f729Sjoerg
3337330f729Sjoerg if (!Mapping.second.isUser())
3347330f729Sjoerg llvm::errs() << " default";
3357330f729Sjoerg if (Mapping.second.isPragma())
3367330f729Sjoerg llvm::errs() << " pragma";
3377330f729Sjoerg if (Mapping.second.hasNoWarningAsError())
3387330f729Sjoerg llvm::errs() << " no-error";
3397330f729Sjoerg if (Mapping.second.hasNoErrorAsFatal())
3407330f729Sjoerg llvm::errs() << " no-fatal";
3417330f729Sjoerg if (Mapping.second.wasUpgradedFromWarning())
3427330f729Sjoerg llvm::errs() << " overruled";
3437330f729Sjoerg llvm::errs() << "\n";
3447330f729Sjoerg }
3457330f729Sjoerg }
3467330f729Sjoerg }
3477330f729Sjoerg }
3487330f729Sjoerg
PushDiagStatePoint(DiagState * State,SourceLocation Loc)3497330f729Sjoerg void DiagnosticsEngine::PushDiagStatePoint(DiagState *State,
3507330f729Sjoerg SourceLocation Loc) {
3517330f729Sjoerg assert(Loc.isValid() && "Adding invalid loc point");
3527330f729Sjoerg DiagStatesByLoc.append(*SourceMgr, Loc, State);
3537330f729Sjoerg }
3547330f729Sjoerg
setSeverity(diag::kind Diag,diag::Severity Map,SourceLocation L)3557330f729Sjoerg void DiagnosticsEngine::setSeverity(diag::kind Diag, diag::Severity Map,
3567330f729Sjoerg SourceLocation L) {
3577330f729Sjoerg assert(Diag < diag::DIAG_UPPER_LIMIT &&
3587330f729Sjoerg "Can only map builtin diagnostics");
3597330f729Sjoerg assert((Diags->isBuiltinWarningOrExtension(Diag) ||
3607330f729Sjoerg (Map == diag::Severity::Fatal || Map == diag::Severity::Error)) &&
3617330f729Sjoerg "Cannot map errors into warnings!");
3627330f729Sjoerg assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
3637330f729Sjoerg
3647330f729Sjoerg // Don't allow a mapping to a warning override an error/fatal mapping.
3657330f729Sjoerg bool WasUpgradedFromWarning = false;
3667330f729Sjoerg if (Map == diag::Severity::Warning) {
3677330f729Sjoerg DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
3687330f729Sjoerg if (Info.getSeverity() == diag::Severity::Error ||
3697330f729Sjoerg Info.getSeverity() == diag::Severity::Fatal) {
3707330f729Sjoerg Map = Info.getSeverity();
3717330f729Sjoerg WasUpgradedFromWarning = true;
3727330f729Sjoerg }
3737330f729Sjoerg }
3747330f729Sjoerg DiagnosticMapping Mapping = makeUserMapping(Map, L);
3757330f729Sjoerg Mapping.setUpgradedFromWarning(WasUpgradedFromWarning);
3767330f729Sjoerg
3777330f729Sjoerg // Common case; setting all the diagnostics of a group in one place.
3787330f729Sjoerg if ((L.isInvalid() || L == DiagStatesByLoc.getCurDiagStateLoc()) &&
3797330f729Sjoerg DiagStatesByLoc.getCurDiagState()) {
3807330f729Sjoerg // FIXME: This is theoretically wrong: if the current state is shared with
3817330f729Sjoerg // some other location (via push/pop) we will change the state for that
3827330f729Sjoerg // other location as well. This cannot currently happen, as we can't update
3837330f729Sjoerg // the diagnostic state at the same location at which we pop.
3847330f729Sjoerg DiagStatesByLoc.getCurDiagState()->setMapping(Diag, Mapping);
3857330f729Sjoerg return;
3867330f729Sjoerg }
3877330f729Sjoerg
3887330f729Sjoerg // A diagnostic pragma occurred, create a new DiagState initialized with
3897330f729Sjoerg // the current one and a new DiagStatePoint to record at which location
3907330f729Sjoerg // the new state became active.
3917330f729Sjoerg DiagStates.push_back(*GetCurDiagState());
3927330f729Sjoerg DiagStates.back().setMapping(Diag, Mapping);
3937330f729Sjoerg PushDiagStatePoint(&DiagStates.back(), L);
3947330f729Sjoerg }
3957330f729Sjoerg
setSeverityForGroup(diag::Flavor Flavor,StringRef Group,diag::Severity Map,SourceLocation Loc)3967330f729Sjoerg bool DiagnosticsEngine::setSeverityForGroup(diag::Flavor Flavor,
3977330f729Sjoerg StringRef Group, diag::Severity Map,
3987330f729Sjoerg SourceLocation Loc) {
3997330f729Sjoerg // Get the diagnostics in this group.
4007330f729Sjoerg SmallVector<diag::kind, 256> GroupDiags;
4017330f729Sjoerg if (Diags->getDiagnosticsInGroup(Flavor, Group, GroupDiags))
4027330f729Sjoerg return true;
4037330f729Sjoerg
4047330f729Sjoerg // Set the mapping.
4057330f729Sjoerg for (diag::kind Diag : GroupDiags)
4067330f729Sjoerg setSeverity(Diag, Map, Loc);
4077330f729Sjoerg
4087330f729Sjoerg return false;
4097330f729Sjoerg }
4107330f729Sjoerg
setDiagnosticGroupWarningAsError(StringRef Group,bool Enabled)4117330f729Sjoerg bool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
4127330f729Sjoerg bool Enabled) {
4137330f729Sjoerg // If we are enabling this feature, just set the diagnostic mappings to map to
4147330f729Sjoerg // errors.
4157330f729Sjoerg if (Enabled)
4167330f729Sjoerg return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
4177330f729Sjoerg diag::Severity::Error);
4187330f729Sjoerg
4197330f729Sjoerg // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
4207330f729Sjoerg // potentially downgrade anything already mapped to be a warning.
4217330f729Sjoerg
4227330f729Sjoerg // Get the diagnostics in this group.
4237330f729Sjoerg SmallVector<diag::kind, 8> GroupDiags;
4247330f729Sjoerg if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
4257330f729Sjoerg GroupDiags))
4267330f729Sjoerg return true;
4277330f729Sjoerg
4287330f729Sjoerg // Perform the mapping change.
4297330f729Sjoerg for (diag::kind Diag : GroupDiags) {
4307330f729Sjoerg DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
4317330f729Sjoerg
4327330f729Sjoerg if (Info.getSeverity() == diag::Severity::Error ||
4337330f729Sjoerg Info.getSeverity() == diag::Severity::Fatal)
4347330f729Sjoerg Info.setSeverity(diag::Severity::Warning);
4357330f729Sjoerg
4367330f729Sjoerg Info.setNoWarningAsError(true);
4377330f729Sjoerg }
4387330f729Sjoerg
4397330f729Sjoerg return false;
4407330f729Sjoerg }
4417330f729Sjoerg
setDiagnosticGroupErrorAsFatal(StringRef Group,bool Enabled)4427330f729Sjoerg bool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
4437330f729Sjoerg bool Enabled) {
4447330f729Sjoerg // If we are enabling this feature, just set the diagnostic mappings to map to
4457330f729Sjoerg // fatal errors.
4467330f729Sjoerg if (Enabled)
4477330f729Sjoerg return setSeverityForGroup(diag::Flavor::WarningOrError, Group,
4487330f729Sjoerg diag::Severity::Fatal);
4497330f729Sjoerg
4507330f729Sjoerg // Otherwise, we want to set the diagnostic mapping's "no Wfatal-errors" bit,
4517330f729Sjoerg // and potentially downgrade anything already mapped to be a fatal error.
4527330f729Sjoerg
4537330f729Sjoerg // Get the diagnostics in this group.
4547330f729Sjoerg SmallVector<diag::kind, 8> GroupDiags;
4557330f729Sjoerg if (Diags->getDiagnosticsInGroup(diag::Flavor::WarningOrError, Group,
4567330f729Sjoerg GroupDiags))
4577330f729Sjoerg return true;
4587330f729Sjoerg
4597330f729Sjoerg // Perform the mapping change.
4607330f729Sjoerg for (diag::kind Diag : GroupDiags) {
4617330f729Sjoerg DiagnosticMapping &Info = GetCurDiagState()->getOrAddMapping(Diag);
4627330f729Sjoerg
4637330f729Sjoerg if (Info.getSeverity() == diag::Severity::Fatal)
4647330f729Sjoerg Info.setSeverity(diag::Severity::Error);
4657330f729Sjoerg
4667330f729Sjoerg Info.setNoErrorAsFatal(true);
4677330f729Sjoerg }
4687330f729Sjoerg
4697330f729Sjoerg return false;
4707330f729Sjoerg }
4717330f729Sjoerg
setSeverityForAll(diag::Flavor Flavor,diag::Severity Map,SourceLocation Loc)4727330f729Sjoerg void DiagnosticsEngine::setSeverityForAll(diag::Flavor Flavor,
4737330f729Sjoerg diag::Severity Map,
4747330f729Sjoerg SourceLocation Loc) {
4757330f729Sjoerg // Get all the diagnostics.
4767330f729Sjoerg std::vector<diag::kind> AllDiags;
4777330f729Sjoerg DiagnosticIDs::getAllDiagnostics(Flavor, AllDiags);
4787330f729Sjoerg
4797330f729Sjoerg // Set the mapping.
4807330f729Sjoerg for (diag::kind Diag : AllDiags)
4817330f729Sjoerg if (Diags->isBuiltinWarningOrExtension(Diag))
4827330f729Sjoerg setSeverity(Diag, Map, Loc);
4837330f729Sjoerg }
4847330f729Sjoerg
Report(const StoredDiagnostic & storedDiag)4857330f729Sjoerg void DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
4867330f729Sjoerg assert(CurDiagID == std::numeric_limits<unsigned>::max() &&
4877330f729Sjoerg "Multiple diagnostics in flight at once!");
4887330f729Sjoerg
4897330f729Sjoerg CurDiagLoc = storedDiag.getLocation();
4907330f729Sjoerg CurDiagID = storedDiag.getID();
491*e038c9c4Sjoerg DiagStorage.NumDiagArgs = 0;
4927330f729Sjoerg
493*e038c9c4Sjoerg DiagStorage.DiagRanges.clear();
494*e038c9c4Sjoerg DiagStorage.DiagRanges.append(storedDiag.range_begin(),
495*e038c9c4Sjoerg storedDiag.range_end());
4967330f729Sjoerg
497*e038c9c4Sjoerg DiagStorage.FixItHints.clear();
498*e038c9c4Sjoerg DiagStorage.FixItHints.append(storedDiag.fixit_begin(),
499*e038c9c4Sjoerg storedDiag.fixit_end());
5007330f729Sjoerg
5017330f729Sjoerg assert(Client && "DiagnosticConsumer not set!");
5027330f729Sjoerg Level DiagLevel = storedDiag.getLevel();
5037330f729Sjoerg Diagnostic Info(this, storedDiag.getMessage());
5047330f729Sjoerg Client->HandleDiagnostic(DiagLevel, Info);
5057330f729Sjoerg if (Client->IncludeInDiagnosticCounts()) {
5067330f729Sjoerg if (DiagLevel == DiagnosticsEngine::Warning)
5077330f729Sjoerg ++NumWarnings;
5087330f729Sjoerg }
5097330f729Sjoerg
5107330f729Sjoerg CurDiagID = std::numeric_limits<unsigned>::max();
5117330f729Sjoerg }
5127330f729Sjoerg
EmitCurrentDiagnostic(bool Force)5137330f729Sjoerg bool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) {
5147330f729Sjoerg assert(getClient() && "DiagnosticClient not set!");
5157330f729Sjoerg
5167330f729Sjoerg bool Emitted;
5177330f729Sjoerg if (Force) {
5187330f729Sjoerg Diagnostic Info(this);
5197330f729Sjoerg
5207330f729Sjoerg // Figure out the diagnostic level of this message.
5217330f729Sjoerg DiagnosticIDs::Level DiagLevel
5227330f729Sjoerg = Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this);
5237330f729Sjoerg
5247330f729Sjoerg Emitted = (DiagLevel != DiagnosticIDs::Ignored);
5257330f729Sjoerg if (Emitted) {
5267330f729Sjoerg // Emit the diagnostic regardless of suppression level.
5277330f729Sjoerg Diags->EmitDiag(*this, DiagLevel);
5287330f729Sjoerg }
5297330f729Sjoerg } else {
5307330f729Sjoerg // Process the diagnostic, sending the accumulated information to the
5317330f729Sjoerg // DiagnosticConsumer.
5327330f729Sjoerg Emitted = ProcessDiag();
5337330f729Sjoerg }
5347330f729Sjoerg
5357330f729Sjoerg // Clear out the current diagnostic object.
5367330f729Sjoerg Clear();
5377330f729Sjoerg
5387330f729Sjoerg // If there was a delayed diagnostic, emit it now.
5397330f729Sjoerg if (!Force && DelayedDiagID)
5407330f729Sjoerg ReportDelayed();
5417330f729Sjoerg
5427330f729Sjoerg return Emitted;
5437330f729Sjoerg }
5447330f729Sjoerg
5457330f729Sjoerg DiagnosticConsumer::~DiagnosticConsumer() = default;
5467330f729Sjoerg
HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,const Diagnostic & Info)5477330f729Sjoerg void DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
5487330f729Sjoerg const Diagnostic &Info) {
5497330f729Sjoerg if (!IncludeInDiagnosticCounts())
5507330f729Sjoerg return;
5517330f729Sjoerg
5527330f729Sjoerg if (DiagLevel == DiagnosticsEngine::Warning)
5537330f729Sjoerg ++NumWarnings;
5547330f729Sjoerg else if (DiagLevel >= DiagnosticsEngine::Error)
5557330f729Sjoerg ++NumErrors;
5567330f729Sjoerg }
5577330f729Sjoerg
5587330f729Sjoerg /// ModifierIs - Return true if the specified modifier matches specified string.
5597330f729Sjoerg template <std::size_t StrLen>
ModifierIs(const char * Modifier,unsigned ModifierLen,const char (& Str)[StrLen])5607330f729Sjoerg static bool ModifierIs(const char *Modifier, unsigned ModifierLen,
5617330f729Sjoerg const char (&Str)[StrLen]) {
5627330f729Sjoerg return StrLen-1 == ModifierLen && memcmp(Modifier, Str, StrLen-1) == 0;
5637330f729Sjoerg }
5647330f729Sjoerg
5657330f729Sjoerg /// ScanForward - Scans forward, looking for the given character, skipping
5667330f729Sjoerg /// nested clauses and escaped characters.
ScanFormat(const char * I,const char * E,char Target)5677330f729Sjoerg static const char *ScanFormat(const char *I, const char *E, char Target) {
5687330f729Sjoerg unsigned Depth = 0;
5697330f729Sjoerg
5707330f729Sjoerg for ( ; I != E; ++I) {
5717330f729Sjoerg if (Depth == 0 && *I == Target) return I;
5727330f729Sjoerg if (Depth != 0 && *I == '}') Depth--;
5737330f729Sjoerg
5747330f729Sjoerg if (*I == '%') {
5757330f729Sjoerg I++;
5767330f729Sjoerg if (I == E) break;
5777330f729Sjoerg
5787330f729Sjoerg // Escaped characters get implicitly skipped here.
5797330f729Sjoerg
5807330f729Sjoerg // Format specifier.
5817330f729Sjoerg if (!isDigit(*I) && !isPunctuation(*I)) {
5827330f729Sjoerg for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
5837330f729Sjoerg if (I == E) break;
5847330f729Sjoerg if (*I == '{')
5857330f729Sjoerg Depth++;
5867330f729Sjoerg }
5877330f729Sjoerg }
5887330f729Sjoerg }
5897330f729Sjoerg return E;
5907330f729Sjoerg }
5917330f729Sjoerg
5927330f729Sjoerg /// HandleSelectModifier - Handle the integer 'select' modifier. This is used
5937330f729Sjoerg /// like this: %select{foo|bar|baz}2. This means that the integer argument
5947330f729Sjoerg /// "%2" has a value from 0-2. If the value is 0, the diagnostic prints 'foo'.
5957330f729Sjoerg /// If the value is 1, it prints 'bar'. If it has the value 2, it prints 'baz'.
5967330f729Sjoerg /// This is very useful for certain classes of variant diagnostics.
HandleSelectModifier(const Diagnostic & DInfo,unsigned ValNo,const char * Argument,unsigned ArgumentLen,SmallVectorImpl<char> & OutStr)5977330f729Sjoerg static void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
5987330f729Sjoerg const char *Argument, unsigned ArgumentLen,
5997330f729Sjoerg SmallVectorImpl<char> &OutStr) {
6007330f729Sjoerg const char *ArgumentEnd = Argument+ArgumentLen;
6017330f729Sjoerg
6027330f729Sjoerg // Skip over 'ValNo' |'s.
6037330f729Sjoerg while (ValNo) {
6047330f729Sjoerg const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
6057330f729Sjoerg assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
6067330f729Sjoerg " larger than the number of options in the diagnostic string!");
6077330f729Sjoerg Argument = NextVal+1; // Skip this string.
6087330f729Sjoerg --ValNo;
6097330f729Sjoerg }
6107330f729Sjoerg
6117330f729Sjoerg // Get the end of the value. This is either the } or the |.
6127330f729Sjoerg const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
6137330f729Sjoerg
6147330f729Sjoerg // Recursively format the result of the select clause into the output string.
6157330f729Sjoerg DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
6167330f729Sjoerg }
6177330f729Sjoerg
6187330f729Sjoerg /// HandleIntegerSModifier - Handle the integer 's' modifier. This adds the
6197330f729Sjoerg /// letter 's' to the string if the value is not 1. This is used in cases like
6207330f729Sjoerg /// this: "you idiot, you have %4 parameter%s4!".
HandleIntegerSModifier(unsigned ValNo,SmallVectorImpl<char> & OutStr)6217330f729Sjoerg static void HandleIntegerSModifier(unsigned ValNo,
6227330f729Sjoerg SmallVectorImpl<char> &OutStr) {
6237330f729Sjoerg if (ValNo != 1)
6247330f729Sjoerg OutStr.push_back('s');
6257330f729Sjoerg }
6267330f729Sjoerg
6277330f729Sjoerg /// HandleOrdinalModifier - Handle the integer 'ord' modifier. This
6287330f729Sjoerg /// prints the ordinal form of the given integer, with 1 corresponding
6297330f729Sjoerg /// to the first ordinal. Currently this is hard-coded to use the
6307330f729Sjoerg /// English form.
HandleOrdinalModifier(unsigned ValNo,SmallVectorImpl<char> & OutStr)6317330f729Sjoerg static void HandleOrdinalModifier(unsigned ValNo,
6327330f729Sjoerg SmallVectorImpl<char> &OutStr) {
6337330f729Sjoerg assert(ValNo != 0 && "ValNo must be strictly positive!");
6347330f729Sjoerg
6357330f729Sjoerg llvm::raw_svector_ostream Out(OutStr);
6367330f729Sjoerg
6377330f729Sjoerg // We could use text forms for the first N ordinals, but the numeric
6387330f729Sjoerg // forms are actually nicer in diagnostics because they stand out.
6397330f729Sjoerg Out << ValNo << llvm::getOrdinalSuffix(ValNo);
6407330f729Sjoerg }
6417330f729Sjoerg
6427330f729Sjoerg /// PluralNumber - Parse an unsigned integer and advance Start.
PluralNumber(const char * & Start,const char * End)6437330f729Sjoerg static unsigned PluralNumber(const char *&Start, const char *End) {
6447330f729Sjoerg // Programming 101: Parse a decimal number :-)
6457330f729Sjoerg unsigned Val = 0;
6467330f729Sjoerg while (Start != End && *Start >= '0' && *Start <= '9') {
6477330f729Sjoerg Val *= 10;
6487330f729Sjoerg Val += *Start - '0';
6497330f729Sjoerg ++Start;
6507330f729Sjoerg }
6517330f729Sjoerg return Val;
6527330f729Sjoerg }
6537330f729Sjoerg
6547330f729Sjoerg /// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
TestPluralRange(unsigned Val,const char * & Start,const char * End)6557330f729Sjoerg static bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
6567330f729Sjoerg if (*Start != '[') {
6577330f729Sjoerg unsigned Ref = PluralNumber(Start, End);
6587330f729Sjoerg return Ref == Val;
6597330f729Sjoerg }
6607330f729Sjoerg
6617330f729Sjoerg ++Start;
6627330f729Sjoerg unsigned Low = PluralNumber(Start, End);
6637330f729Sjoerg assert(*Start == ',' && "Bad plural expression syntax: expected ,");
6647330f729Sjoerg ++Start;
6657330f729Sjoerg unsigned High = PluralNumber(Start, End);
6667330f729Sjoerg assert(*Start == ']' && "Bad plural expression syntax: expected )");
6677330f729Sjoerg ++Start;
6687330f729Sjoerg return Low <= Val && Val <= High;
6697330f729Sjoerg }
6707330f729Sjoerg
6717330f729Sjoerg /// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
EvalPluralExpr(unsigned ValNo,const char * Start,const char * End)6727330f729Sjoerg static bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
6737330f729Sjoerg // Empty condition?
6747330f729Sjoerg if (*Start == ':')
6757330f729Sjoerg return true;
6767330f729Sjoerg
6777330f729Sjoerg while (true) {
6787330f729Sjoerg char C = *Start;
6797330f729Sjoerg if (C == '%') {
6807330f729Sjoerg // Modulo expression
6817330f729Sjoerg ++Start;
6827330f729Sjoerg unsigned Arg = PluralNumber(Start, End);
6837330f729Sjoerg assert(*Start == '=' && "Bad plural expression syntax: expected =");
6847330f729Sjoerg ++Start;
6857330f729Sjoerg unsigned ValMod = ValNo % Arg;
6867330f729Sjoerg if (TestPluralRange(ValMod, Start, End))
6877330f729Sjoerg return true;
6887330f729Sjoerg } else {
6897330f729Sjoerg assert((C == '[' || (C >= '0' && C <= '9')) &&
6907330f729Sjoerg "Bad plural expression syntax: unexpected character");
6917330f729Sjoerg // Range expression
6927330f729Sjoerg if (TestPluralRange(ValNo, Start, End))
6937330f729Sjoerg return true;
6947330f729Sjoerg }
6957330f729Sjoerg
6967330f729Sjoerg // Scan for next or-expr part.
6977330f729Sjoerg Start = std::find(Start, End, ',');
6987330f729Sjoerg if (Start == End)
6997330f729Sjoerg break;
7007330f729Sjoerg ++Start;
7017330f729Sjoerg }
7027330f729Sjoerg return false;
7037330f729Sjoerg }
7047330f729Sjoerg
7057330f729Sjoerg /// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
7067330f729Sjoerg /// for complex plural forms, or in languages where all plurals are complex.
7077330f729Sjoerg /// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
7087330f729Sjoerg /// conditions that are tested in order, the form corresponding to the first
7097330f729Sjoerg /// that applies being emitted. The empty condition is always true, making the
7107330f729Sjoerg /// last form a default case.
7117330f729Sjoerg /// Conditions are simple boolean expressions, where n is the number argument.
7127330f729Sjoerg /// Here are the rules.
7137330f729Sjoerg /// condition := expression | empty
7147330f729Sjoerg /// empty := -> always true
7157330f729Sjoerg /// expression := numeric [',' expression] -> logical or
7167330f729Sjoerg /// numeric := range -> true if n in range
7177330f729Sjoerg /// | '%' number '=' range -> true if n % number in range
7187330f729Sjoerg /// range := number
7197330f729Sjoerg /// | '[' number ',' number ']' -> ranges are inclusive both ends
7207330f729Sjoerg ///
7217330f729Sjoerg /// Here are some examples from the GNU gettext manual written in this form:
7227330f729Sjoerg /// English:
7237330f729Sjoerg /// {1:form0|:form1}
7247330f729Sjoerg /// Latvian:
7257330f729Sjoerg /// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
7267330f729Sjoerg /// Gaeilge:
7277330f729Sjoerg /// {1:form0|2:form1|:form2}
7287330f729Sjoerg /// Romanian:
7297330f729Sjoerg /// {1:form0|0,%100=[1,19]:form1|:form2}
7307330f729Sjoerg /// Lithuanian:
7317330f729Sjoerg /// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
7327330f729Sjoerg /// Russian (requires repeated form):
7337330f729Sjoerg /// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
7347330f729Sjoerg /// Slovak
7357330f729Sjoerg /// {1:form0|[2,4]:form1|:form2}
7367330f729Sjoerg /// Polish (requires repeated form):
7377330f729Sjoerg /// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
HandlePluralModifier(const Diagnostic & DInfo,unsigned ValNo,const char * Argument,unsigned ArgumentLen,SmallVectorImpl<char> & OutStr)7387330f729Sjoerg static void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
7397330f729Sjoerg const char *Argument, unsigned ArgumentLen,
7407330f729Sjoerg SmallVectorImpl<char> &OutStr) {
7417330f729Sjoerg const char *ArgumentEnd = Argument + ArgumentLen;
7427330f729Sjoerg while (true) {
7437330f729Sjoerg assert(Argument < ArgumentEnd && "Plural expression didn't match.");
7447330f729Sjoerg const char *ExprEnd = Argument;
7457330f729Sjoerg while (*ExprEnd != ':') {
7467330f729Sjoerg assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
7477330f729Sjoerg ++ExprEnd;
7487330f729Sjoerg }
7497330f729Sjoerg if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
7507330f729Sjoerg Argument = ExprEnd + 1;
7517330f729Sjoerg ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
7527330f729Sjoerg
7537330f729Sjoerg // Recursively format the result of the plural clause into the
7547330f729Sjoerg // output string.
7557330f729Sjoerg DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
7567330f729Sjoerg return;
7577330f729Sjoerg }
7587330f729Sjoerg Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
7597330f729Sjoerg }
7607330f729Sjoerg }
7617330f729Sjoerg
7627330f729Sjoerg /// Returns the friendly description for a token kind that will appear
7637330f729Sjoerg /// without quotes in diagnostic messages. These strings may be translatable in
7647330f729Sjoerg /// future.
getTokenDescForDiagnostic(tok::TokenKind Kind)7657330f729Sjoerg static const char *getTokenDescForDiagnostic(tok::TokenKind Kind) {
7667330f729Sjoerg switch (Kind) {
7677330f729Sjoerg case tok::identifier:
7687330f729Sjoerg return "identifier";
7697330f729Sjoerg default:
7707330f729Sjoerg return nullptr;
7717330f729Sjoerg }
7727330f729Sjoerg }
7737330f729Sjoerg
7747330f729Sjoerg /// FormatDiagnostic - Format this diagnostic into a string, substituting the
7757330f729Sjoerg /// formal arguments into the %0 slots. The result is appended onto the Str
7767330f729Sjoerg /// array.
7777330f729Sjoerg void Diagnostic::
FormatDiagnostic(SmallVectorImpl<char> & OutStr) const7787330f729Sjoerg FormatDiagnostic(SmallVectorImpl<char> &OutStr) const {
7797330f729Sjoerg if (!StoredDiagMessage.empty()) {
7807330f729Sjoerg OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
7817330f729Sjoerg return;
7827330f729Sjoerg }
7837330f729Sjoerg
7847330f729Sjoerg StringRef Diag =
7857330f729Sjoerg getDiags()->getDiagnosticIDs()->getDescription(getID());
7867330f729Sjoerg
7877330f729Sjoerg FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
7887330f729Sjoerg }
7897330f729Sjoerg
7907330f729Sjoerg void Diagnostic::
FormatDiagnostic(const char * DiagStr,const char * DiagEnd,SmallVectorImpl<char> & OutStr) const7917330f729Sjoerg FormatDiagnostic(const char *DiagStr, const char *DiagEnd,
7927330f729Sjoerg SmallVectorImpl<char> &OutStr) const {
7937330f729Sjoerg // When the diagnostic string is only "%0", the entire string is being given
7947330f729Sjoerg // by an outside source. Remove unprintable characters from this string
7957330f729Sjoerg // and skip all the other string processing.
7967330f729Sjoerg if (DiagEnd - DiagStr == 2 &&
7977330f729Sjoerg StringRef(DiagStr, DiagEnd - DiagStr).equals("%0") &&
7987330f729Sjoerg getArgKind(0) == DiagnosticsEngine::ak_std_string) {
7997330f729Sjoerg const std::string &S = getArgStdStr(0);
8007330f729Sjoerg for (char c : S) {
8017330f729Sjoerg if (llvm::sys::locale::isPrint(c) || c == '\t') {
8027330f729Sjoerg OutStr.push_back(c);
8037330f729Sjoerg }
8047330f729Sjoerg }
8057330f729Sjoerg return;
8067330f729Sjoerg }
8077330f729Sjoerg
8087330f729Sjoerg /// FormattedArgs - Keep track of all of the arguments formatted by
8097330f729Sjoerg /// ConvertArgToString and pass them into subsequent calls to
8107330f729Sjoerg /// ConvertArgToString, allowing the implementation to avoid redundancies in
8117330f729Sjoerg /// obvious cases.
8127330f729Sjoerg SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs;
8137330f729Sjoerg
8147330f729Sjoerg /// QualTypeVals - Pass a vector of arrays so that QualType names can be
8157330f729Sjoerg /// compared to see if more information is needed to be printed.
8167330f729Sjoerg SmallVector<intptr_t, 2> QualTypeVals;
817*e038c9c4Sjoerg SmallString<64> Tree;
8187330f729Sjoerg
8197330f729Sjoerg for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
8207330f729Sjoerg if (getArgKind(i) == DiagnosticsEngine::ak_qualtype)
8217330f729Sjoerg QualTypeVals.push_back(getRawArg(i));
8227330f729Sjoerg
8237330f729Sjoerg while (DiagStr != DiagEnd) {
8247330f729Sjoerg if (DiagStr[0] != '%') {
8257330f729Sjoerg // Append non-%0 substrings to Str if we have one.
8267330f729Sjoerg const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
8277330f729Sjoerg OutStr.append(DiagStr, StrEnd);
8287330f729Sjoerg DiagStr = StrEnd;
8297330f729Sjoerg continue;
8307330f729Sjoerg } else if (isPunctuation(DiagStr[1])) {
8317330f729Sjoerg OutStr.push_back(DiagStr[1]); // %% -> %.
8327330f729Sjoerg DiagStr += 2;
8337330f729Sjoerg continue;
8347330f729Sjoerg }
8357330f729Sjoerg
8367330f729Sjoerg // Skip the %.
8377330f729Sjoerg ++DiagStr;
8387330f729Sjoerg
8397330f729Sjoerg // This must be a placeholder for a diagnostic argument. The format for a
8407330f729Sjoerg // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
8417330f729Sjoerg // The digit is a number from 0-9 indicating which argument this comes from.
8427330f729Sjoerg // The modifier is a string of digits from the set [-a-z]+, arguments is a
8437330f729Sjoerg // brace enclosed string.
8447330f729Sjoerg const char *Modifier = nullptr, *Argument = nullptr;
8457330f729Sjoerg unsigned ModifierLen = 0, ArgumentLen = 0;
8467330f729Sjoerg
8477330f729Sjoerg // Check to see if we have a modifier. If so eat it.
8487330f729Sjoerg if (!isDigit(DiagStr[0])) {
8497330f729Sjoerg Modifier = DiagStr;
8507330f729Sjoerg while (DiagStr[0] == '-' ||
8517330f729Sjoerg (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
8527330f729Sjoerg ++DiagStr;
8537330f729Sjoerg ModifierLen = DiagStr-Modifier;
8547330f729Sjoerg
8557330f729Sjoerg // If we have an argument, get it next.
8567330f729Sjoerg if (DiagStr[0] == '{') {
8577330f729Sjoerg ++DiagStr; // Skip {.
8587330f729Sjoerg Argument = DiagStr;
8597330f729Sjoerg
8607330f729Sjoerg DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
8617330f729Sjoerg assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
8627330f729Sjoerg ArgumentLen = DiagStr-Argument;
8637330f729Sjoerg ++DiagStr; // Skip }.
8647330f729Sjoerg }
8657330f729Sjoerg }
8667330f729Sjoerg
8677330f729Sjoerg assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
8687330f729Sjoerg unsigned ArgNo = *DiagStr++ - '0';
8697330f729Sjoerg
8707330f729Sjoerg // Only used for type diffing.
8717330f729Sjoerg unsigned ArgNo2 = ArgNo;
8727330f729Sjoerg
8737330f729Sjoerg DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
8747330f729Sjoerg if (ModifierIs(Modifier, ModifierLen, "diff")) {
8757330f729Sjoerg assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
8767330f729Sjoerg "Invalid format for diff modifier");
8777330f729Sjoerg ++DiagStr; // Comma.
8787330f729Sjoerg ArgNo2 = *DiagStr++ - '0';
8797330f729Sjoerg DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2);
8807330f729Sjoerg if (Kind == DiagnosticsEngine::ak_qualtype &&
8817330f729Sjoerg Kind2 == DiagnosticsEngine::ak_qualtype)
8827330f729Sjoerg Kind = DiagnosticsEngine::ak_qualtype_pair;
8837330f729Sjoerg else {
8847330f729Sjoerg // %diff only supports QualTypes. For other kinds of arguments,
8857330f729Sjoerg // use the default printing. For example, if the modifier is:
8867330f729Sjoerg // "%diff{compare $ to $|other text}1,2"
8877330f729Sjoerg // treat it as:
8887330f729Sjoerg // "compare %1 to %2"
8897330f729Sjoerg const char *ArgumentEnd = Argument + ArgumentLen;
8907330f729Sjoerg const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
8917330f729Sjoerg assert(ScanFormat(Pipe + 1, ArgumentEnd, '|') == ArgumentEnd &&
8927330f729Sjoerg "Found too many '|'s in a %diff modifier!");
8937330f729Sjoerg const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
8947330f729Sjoerg const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
8957330f729Sjoerg const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
8967330f729Sjoerg const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
8977330f729Sjoerg FormatDiagnostic(Argument, FirstDollar, OutStr);
8987330f729Sjoerg FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
8997330f729Sjoerg FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
9007330f729Sjoerg FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
9017330f729Sjoerg FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
9027330f729Sjoerg continue;
9037330f729Sjoerg }
9047330f729Sjoerg }
9057330f729Sjoerg
9067330f729Sjoerg switch (Kind) {
9077330f729Sjoerg // ---- STRINGS ----
9087330f729Sjoerg case DiagnosticsEngine::ak_std_string: {
9097330f729Sjoerg const std::string &S = getArgStdStr(ArgNo);
9107330f729Sjoerg assert(ModifierLen == 0 && "No modifiers for strings yet");
9117330f729Sjoerg OutStr.append(S.begin(), S.end());
9127330f729Sjoerg break;
9137330f729Sjoerg }
9147330f729Sjoerg case DiagnosticsEngine::ak_c_string: {
9157330f729Sjoerg const char *S = getArgCStr(ArgNo);
9167330f729Sjoerg assert(ModifierLen == 0 && "No modifiers for strings yet");
9177330f729Sjoerg
9187330f729Sjoerg // Don't crash if get passed a null pointer by accident.
9197330f729Sjoerg if (!S)
9207330f729Sjoerg S = "(null)";
9217330f729Sjoerg
9227330f729Sjoerg OutStr.append(S, S + strlen(S));
9237330f729Sjoerg break;
9247330f729Sjoerg }
9257330f729Sjoerg // ---- INTEGERS ----
9267330f729Sjoerg case DiagnosticsEngine::ak_sint: {
9277330f729Sjoerg int Val = getArgSInt(ArgNo);
9287330f729Sjoerg
9297330f729Sjoerg if (ModifierIs(Modifier, ModifierLen, "select")) {
9307330f729Sjoerg HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
9317330f729Sjoerg OutStr);
9327330f729Sjoerg } else if (ModifierIs(Modifier, ModifierLen, "s")) {
9337330f729Sjoerg HandleIntegerSModifier(Val, OutStr);
9347330f729Sjoerg } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
9357330f729Sjoerg HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
9367330f729Sjoerg OutStr);
9377330f729Sjoerg } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
9387330f729Sjoerg HandleOrdinalModifier((unsigned)Val, OutStr);
9397330f729Sjoerg } else {
9407330f729Sjoerg assert(ModifierLen == 0 && "Unknown integer modifier");
9417330f729Sjoerg llvm::raw_svector_ostream(OutStr) << Val;
9427330f729Sjoerg }
9437330f729Sjoerg break;
9447330f729Sjoerg }
9457330f729Sjoerg case DiagnosticsEngine::ak_uint: {
9467330f729Sjoerg unsigned Val = getArgUInt(ArgNo);
9477330f729Sjoerg
9487330f729Sjoerg if (ModifierIs(Modifier, ModifierLen, "select")) {
9497330f729Sjoerg HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
9507330f729Sjoerg } else if (ModifierIs(Modifier, ModifierLen, "s")) {
9517330f729Sjoerg HandleIntegerSModifier(Val, OutStr);
9527330f729Sjoerg } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
9537330f729Sjoerg HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
9547330f729Sjoerg OutStr);
9557330f729Sjoerg } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
9567330f729Sjoerg HandleOrdinalModifier(Val, OutStr);
9577330f729Sjoerg } else {
9587330f729Sjoerg assert(ModifierLen == 0 && "Unknown integer modifier");
9597330f729Sjoerg llvm::raw_svector_ostream(OutStr) << Val;
9607330f729Sjoerg }
9617330f729Sjoerg break;
9627330f729Sjoerg }
9637330f729Sjoerg // ---- TOKEN SPELLINGS ----
9647330f729Sjoerg case DiagnosticsEngine::ak_tokenkind: {
9657330f729Sjoerg tok::TokenKind Kind = static_cast<tok::TokenKind>(getRawArg(ArgNo));
9667330f729Sjoerg assert(ModifierLen == 0 && "No modifiers for token kinds yet");
9677330f729Sjoerg
9687330f729Sjoerg llvm::raw_svector_ostream Out(OutStr);
9697330f729Sjoerg if (const char *S = tok::getPunctuatorSpelling(Kind))
9707330f729Sjoerg // Quoted token spelling for punctuators.
9717330f729Sjoerg Out << '\'' << S << '\'';
9727330f729Sjoerg else if (const char *S = tok::getKeywordSpelling(Kind))
9737330f729Sjoerg // Unquoted token spelling for keywords.
9747330f729Sjoerg Out << S;
9757330f729Sjoerg else if (const char *S = getTokenDescForDiagnostic(Kind))
9767330f729Sjoerg // Unquoted translatable token name.
9777330f729Sjoerg Out << S;
9787330f729Sjoerg else if (const char *S = tok::getTokenName(Kind))
9797330f729Sjoerg // Debug name, shouldn't appear in user-facing diagnostics.
9807330f729Sjoerg Out << '<' << S << '>';
9817330f729Sjoerg else
9827330f729Sjoerg Out << "(null)";
9837330f729Sjoerg break;
9847330f729Sjoerg }
9857330f729Sjoerg // ---- NAMES and TYPES ----
9867330f729Sjoerg case DiagnosticsEngine::ak_identifierinfo: {
9877330f729Sjoerg const IdentifierInfo *II = getArgIdentifier(ArgNo);
9887330f729Sjoerg assert(ModifierLen == 0 && "No modifiers for strings yet");
9897330f729Sjoerg
9907330f729Sjoerg // Don't crash if get passed a null pointer by accident.
9917330f729Sjoerg if (!II) {
9927330f729Sjoerg const char *S = "(null)";
9937330f729Sjoerg OutStr.append(S, S + strlen(S));
9947330f729Sjoerg continue;
9957330f729Sjoerg }
9967330f729Sjoerg
9977330f729Sjoerg llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
9987330f729Sjoerg break;
9997330f729Sjoerg }
1000*e038c9c4Sjoerg case DiagnosticsEngine::ak_addrspace:
10017330f729Sjoerg case DiagnosticsEngine::ak_qual:
10027330f729Sjoerg case DiagnosticsEngine::ak_qualtype:
10037330f729Sjoerg case DiagnosticsEngine::ak_declarationname:
10047330f729Sjoerg case DiagnosticsEngine::ak_nameddecl:
10057330f729Sjoerg case DiagnosticsEngine::ak_nestednamespec:
10067330f729Sjoerg case DiagnosticsEngine::ak_declcontext:
10077330f729Sjoerg case DiagnosticsEngine::ak_attr:
10087330f729Sjoerg getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
10097330f729Sjoerg StringRef(Modifier, ModifierLen),
10107330f729Sjoerg StringRef(Argument, ArgumentLen),
10117330f729Sjoerg FormattedArgs,
10127330f729Sjoerg OutStr, QualTypeVals);
10137330f729Sjoerg break;
10147330f729Sjoerg case DiagnosticsEngine::ak_qualtype_pair: {
10157330f729Sjoerg // Create a struct with all the info needed for printing.
10167330f729Sjoerg TemplateDiffTypes TDT;
10177330f729Sjoerg TDT.FromType = getRawArg(ArgNo);
10187330f729Sjoerg TDT.ToType = getRawArg(ArgNo2);
10197330f729Sjoerg TDT.ElideType = getDiags()->ElideType;
10207330f729Sjoerg TDT.ShowColors = getDiags()->ShowColors;
10217330f729Sjoerg TDT.TemplateDiffUsed = false;
10227330f729Sjoerg intptr_t val = reinterpret_cast<intptr_t>(&TDT);
10237330f729Sjoerg
10247330f729Sjoerg const char *ArgumentEnd = Argument + ArgumentLen;
10257330f729Sjoerg const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
10267330f729Sjoerg
10277330f729Sjoerg // Print the tree. If this diagnostic already has a tree, skip the
10287330f729Sjoerg // second tree.
10297330f729Sjoerg if (getDiags()->PrintTemplateTree && Tree.empty()) {
10307330f729Sjoerg TDT.PrintFromType = true;
10317330f729Sjoerg TDT.PrintTree = true;
10327330f729Sjoerg getDiags()->ConvertArgToString(Kind, val,
10337330f729Sjoerg StringRef(Modifier, ModifierLen),
10347330f729Sjoerg StringRef(Argument, ArgumentLen),
10357330f729Sjoerg FormattedArgs,
10367330f729Sjoerg Tree, QualTypeVals);
10377330f729Sjoerg // If there is no tree information, fall back to regular printing.
10387330f729Sjoerg if (!Tree.empty()) {
10397330f729Sjoerg FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
10407330f729Sjoerg break;
10417330f729Sjoerg }
10427330f729Sjoerg }
10437330f729Sjoerg
10447330f729Sjoerg // Non-tree printing, also the fall-back when tree printing fails.
10457330f729Sjoerg // The fall-back is triggered when the types compared are not templates.
10467330f729Sjoerg const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
10477330f729Sjoerg const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
10487330f729Sjoerg
10497330f729Sjoerg // Append before text
10507330f729Sjoerg FormatDiagnostic(Argument, FirstDollar, OutStr);
10517330f729Sjoerg
10527330f729Sjoerg // Append first type
10537330f729Sjoerg TDT.PrintTree = false;
10547330f729Sjoerg TDT.PrintFromType = true;
10557330f729Sjoerg getDiags()->ConvertArgToString(Kind, val,
10567330f729Sjoerg StringRef(Modifier, ModifierLen),
10577330f729Sjoerg StringRef(Argument, ArgumentLen),
10587330f729Sjoerg FormattedArgs,
10597330f729Sjoerg OutStr, QualTypeVals);
10607330f729Sjoerg if (!TDT.TemplateDiffUsed)
10617330f729Sjoerg FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
10627330f729Sjoerg TDT.FromType));
10637330f729Sjoerg
10647330f729Sjoerg // Append middle text
10657330f729Sjoerg FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
10667330f729Sjoerg
10677330f729Sjoerg // Append second type
10687330f729Sjoerg TDT.PrintFromType = false;
10697330f729Sjoerg getDiags()->ConvertArgToString(Kind, val,
10707330f729Sjoerg StringRef(Modifier, ModifierLen),
10717330f729Sjoerg StringRef(Argument, ArgumentLen),
10727330f729Sjoerg FormattedArgs,
10737330f729Sjoerg OutStr, QualTypeVals);
10747330f729Sjoerg if (!TDT.TemplateDiffUsed)
10757330f729Sjoerg FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
10767330f729Sjoerg TDT.ToType));
10777330f729Sjoerg
10787330f729Sjoerg // Append end text
10797330f729Sjoerg FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
10807330f729Sjoerg break;
10817330f729Sjoerg }
10827330f729Sjoerg }
10837330f729Sjoerg
10847330f729Sjoerg // Remember this argument info for subsequent formatting operations. Turn
10857330f729Sjoerg // std::strings into a null terminated string to make it be the same case as
10867330f729Sjoerg // all the other ones.
10877330f729Sjoerg if (Kind == DiagnosticsEngine::ak_qualtype_pair)
10887330f729Sjoerg continue;
10897330f729Sjoerg else if (Kind != DiagnosticsEngine::ak_std_string)
10907330f729Sjoerg FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
10917330f729Sjoerg else
10927330f729Sjoerg FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,
10937330f729Sjoerg (intptr_t)getArgStdStr(ArgNo).c_str()));
10947330f729Sjoerg }
10957330f729Sjoerg
10967330f729Sjoerg // Append the type tree to the end of the diagnostics.
10977330f729Sjoerg OutStr.append(Tree.begin(), Tree.end());
10987330f729Sjoerg }
10997330f729Sjoerg
StoredDiagnostic(DiagnosticsEngine::Level Level,unsigned ID,StringRef Message)11007330f729Sjoerg StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
11017330f729Sjoerg StringRef Message)
11027330f729Sjoerg : ID(ID), Level(Level), Message(Message) {}
11037330f729Sjoerg
StoredDiagnostic(DiagnosticsEngine::Level Level,const Diagnostic & Info)11047330f729Sjoerg StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
11057330f729Sjoerg const Diagnostic &Info)
11067330f729Sjoerg : ID(Info.getID()), Level(Level) {
11077330f729Sjoerg assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
11087330f729Sjoerg "Valid source location without setting a source manager for diagnostic");
11097330f729Sjoerg if (Info.getLocation().isValid())
11107330f729Sjoerg Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
11117330f729Sjoerg SmallString<64> Message;
11127330f729Sjoerg Info.FormatDiagnostic(Message);
11137330f729Sjoerg this->Message.assign(Message.begin(), Message.end());
11147330f729Sjoerg this->Ranges.assign(Info.getRanges().begin(), Info.getRanges().end());
11157330f729Sjoerg this->FixIts.assign(Info.getFixItHints().begin(), Info.getFixItHints().end());
11167330f729Sjoerg }
11177330f729Sjoerg
StoredDiagnostic(DiagnosticsEngine::Level Level,unsigned ID,StringRef Message,FullSourceLoc Loc,ArrayRef<CharSourceRange> Ranges,ArrayRef<FixItHint> FixIts)11187330f729Sjoerg StoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
11197330f729Sjoerg StringRef Message, FullSourceLoc Loc,
11207330f729Sjoerg ArrayRef<CharSourceRange> Ranges,
11217330f729Sjoerg ArrayRef<FixItHint> FixIts)
11227330f729Sjoerg : ID(ID), Level(Level), Loc(Loc), Message(Message),
11237330f729Sjoerg Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
11247330f729Sjoerg {
11257330f729Sjoerg }
11267330f729Sjoerg
11277330f729Sjoerg /// IncludeInDiagnosticCounts - This method (whose default implementation
11287330f729Sjoerg /// returns true) indicates whether the diagnostics handled by this
11297330f729Sjoerg /// DiagnosticConsumer should be included in the number of diagnostics
11307330f729Sjoerg /// reported by DiagnosticsEngine.
IncludeInDiagnosticCounts() const11317330f729Sjoerg bool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
11327330f729Sjoerg
anchor()11337330f729Sjoerg void IgnoringDiagConsumer::anchor() {}
11347330f729Sjoerg
11357330f729Sjoerg ForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() = default;
11367330f729Sjoerg
HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,const Diagnostic & Info)11377330f729Sjoerg void ForwardingDiagnosticConsumer::HandleDiagnostic(
11387330f729Sjoerg DiagnosticsEngine::Level DiagLevel,
11397330f729Sjoerg const Diagnostic &Info) {
11407330f729Sjoerg Target.HandleDiagnostic(DiagLevel, Info);
11417330f729Sjoerg }
11427330f729Sjoerg
clear()11437330f729Sjoerg void ForwardingDiagnosticConsumer::clear() {
11447330f729Sjoerg DiagnosticConsumer::clear();
11457330f729Sjoerg Target.clear();
11467330f729Sjoerg }
11477330f729Sjoerg
IncludeInDiagnosticCounts() const11487330f729Sjoerg bool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
11497330f729Sjoerg return Target.IncludeInDiagnosticCounts();
11507330f729Sjoerg }
11517330f729Sjoerg
DiagStorageAllocator()1152*e038c9c4Sjoerg PartialDiagnostic::DiagStorageAllocator::DiagStorageAllocator() {
11537330f729Sjoerg for (unsigned I = 0; I != NumCached; ++I)
11547330f729Sjoerg FreeList[I] = Cached + I;
11557330f729Sjoerg NumFreeListEntries = NumCached;
11567330f729Sjoerg }
11577330f729Sjoerg
~DiagStorageAllocator()1158*e038c9c4Sjoerg PartialDiagnostic::DiagStorageAllocator::~DiagStorageAllocator() {
11597330f729Sjoerg // Don't assert if we are in a CrashRecovery context, as this invariant may
11607330f729Sjoerg // be invalidated during a crash.
11617330f729Sjoerg assert((NumFreeListEntries == NumCached ||
11627330f729Sjoerg llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
11637330f729Sjoerg "A partial is on the lam");
11647330f729Sjoerg }
11657330f729Sjoerg
11667330f729Sjoerg char DiagnosticError::ID;
1167