1193326Sed//===--- Diagnostic.cpp - C Language Family Diagnostic Handling -----------===//
2193326Sed//
3193326Sed//                     The LLVM Compiler Infrastructure
4193326Sed//
5193326Sed// This file is distributed under the University of Illinois Open Source
6193326Sed// License. See LICENSE.TXT for details.
7193326Sed//
8193326Sed//===----------------------------------------------------------------------===//
9193326Sed//
10193326Sed//  This file implements the Diagnostic-related interfaces.
11193326Sed//
12193326Sed//===----------------------------------------------------------------------===//
13193326Sed
14249423Sdim#include "clang/Basic/CharInfo.h"
15207619Srdivacky#include "clang/Basic/Diagnostic.h"
16243830Sdim#include "clang/Basic/DiagnosticOptions.h"
17193326Sed#include "clang/Basic/IdentifierTable.h"
18207619Srdivacky#include "clang/Basic/PartialDiagnostic.h"
19234353Sdim#include "llvm/ADT/SmallString.h"
20243830Sdim#include "llvm/ADT/StringExtras.h"
21249423Sdim#include "llvm/Support/CrashRecoveryContext.h"
22198398Srdivacky#include "llvm/Support/raw_ostream.h"
23221345Sdim
24193326Sedusing namespace clang;
25193326Sed
26226633Sdimstatic void DummyArgToStringFn(DiagnosticsEngine::ArgumentKind AK, intptr_t QT,
27193326Sed                               const char *Modifier, unsigned ML,
28193326Sed                               const char *Argument, unsigned ArgLen,
29226633Sdim                               const DiagnosticsEngine::ArgumentValue *PrevArgs,
30198398Srdivacky                               unsigned NumPrevArgs,
31226633Sdim                               SmallVectorImpl<char> &Output,
32224145Sdim                               void *Cookie,
33234353Sdim                               ArrayRef<intptr_t> QualTypeVals) {
34193326Sed  const char *Str = "<can't format argument>";
35193326Sed  Output.append(Str, Str+strlen(Str));
36193326Sed}
37193326Sed
38193326Sed
39226633SdimDiagnosticsEngine::DiagnosticsEngine(
40234353Sdim                       const IntrusiveRefCntPtr<DiagnosticIDs> &diags,
41243830Sdim                       DiagnosticOptions *DiagOpts,
42226633Sdim                       DiagnosticConsumer *client, bool ShouldOwnClient)
43243830Sdim  : Diags(diags), DiagOpts(DiagOpts), Client(client),
44243830Sdim    OwnsDiagClient(ShouldOwnClient), SourceMgr(0) {
45212904Sdim  ArgToStringFn = DummyArgToStringFn;
46212904Sdim  ArgToStringCookie = 0;
47212904Sdim
48193326Sed  AllExtensionsSilenced = 0;
49193326Sed  IgnoreAllWarnings = false;
50193326Sed  WarningsAsErrors = false;
51226633Sdim  EnableAllWarnings = false;
52201361Srdivacky  ErrorsAsFatal = false;
53193326Sed  SuppressSystemWarnings = false;
54198092Srdivacky  SuppressAllDiagnostics = false;
55239462Sdim  ElideType = true;
56239462Sdim  PrintTemplateTree = false;
57239462Sdim  ShowColors = false;
58210299Sed  ShowOverloads = Ovl_All;
59193326Sed  ExtBehavior = Ext_Ignore;
60198092Srdivacky
61207619Srdivacky  ErrorLimit = 0;
62207619Srdivacky  TemplateBacktraceLimit = 0;
63234353Sdim  ConstexprBacktraceLimit = 0;
64198092Srdivacky
65212904Sdim  Reset();
66193326Sed}
67193326Sed
68226633SdimDiagnosticsEngine::~DiagnosticsEngine() {
69218893Sdim  if (OwnsDiagClient)
70218893Sdim    delete Client;
71193326Sed}
72193326Sed
73226633Sdimvoid DiagnosticsEngine::setClient(DiagnosticConsumer *client,
74226633Sdim                                  bool ShouldOwnClient) {
75218893Sdim  if (OwnsDiagClient && Client)
76218893Sdim    delete Client;
77218893Sdim
78218893Sdim  Client = client;
79218893Sdim  OwnsDiagClient = ShouldOwnClient;
80218893Sdim}
81198092Srdivacky
82226633Sdimvoid DiagnosticsEngine::pushMappings(SourceLocation Loc) {
83218893Sdim  DiagStateOnPushStack.push_back(GetCurDiagState());
84198092Srdivacky}
85198092Srdivacky
86226633Sdimbool DiagnosticsEngine::popMappings(SourceLocation Loc) {
87218893Sdim  if (DiagStateOnPushStack.empty())
88198092Srdivacky    return false;
89198092Srdivacky
90218893Sdim  if (DiagStateOnPushStack.back() != GetCurDiagState()) {
91218893Sdim    // State changed at some point between push/pop.
92218893Sdim    PushDiagStatePoint(DiagStateOnPushStack.back(), Loc);
93218893Sdim  }
94218893Sdim  DiagStateOnPushStack.pop_back();
95198092Srdivacky  return true;
96198092Srdivacky}
97198092Srdivacky
98226633Sdimvoid DiagnosticsEngine::Reset() {
99212904Sdim  ErrorOccurred = false;
100249423Sdim  UncompilableErrorOccurred = false;
101212904Sdim  FatalErrorOccurred = false;
102224145Sdim  UnrecoverableErrorOccurred = false;
103212904Sdim
104212904Sdim  NumWarnings = 0;
105212904Sdim  NumErrors = 0;
106212904Sdim  NumErrorsSuppressed = 0;
107226633Sdim  TrapNumErrorsOccurred = 0;
108226633Sdim  TrapNumUnrecoverableErrorsOccurred = 0;
109224145Sdim
110212904Sdim  CurDiagID = ~0U;
111249423Sdim  LastDiagLevel = DiagnosticIDs::Ignored;
112212904Sdim  DelayedDiagID = 0;
113221345Sdim
114221345Sdim  // Clear state related to #pragma diagnostic.
115221345Sdim  DiagStates.clear();
116221345Sdim  DiagStatePoints.clear();
117221345Sdim  DiagStateOnPushStack.clear();
118221345Sdim
119221345Sdim  // Create a DiagState and DiagStatePoint representing diagnostic changes
120221345Sdim  // through command-line.
121221345Sdim  DiagStates.push_back(DiagState());
122239462Sdim  DiagStatePoints.push_back(DiagStatePoint(&DiagStates.back(), FullSourceLoc()));
123212904Sdim}
124193326Sed
125226633Sdimvoid DiagnosticsEngine::SetDelayedDiagnostic(unsigned DiagID, StringRef Arg1,
126234353Sdim                                             StringRef Arg2) {
127206084Srdivacky  if (DelayedDiagID)
128206084Srdivacky    return;
129206084Srdivacky
130206084Srdivacky  DelayedDiagID = DiagID;
131206084Srdivacky  DelayedDiagArg1 = Arg1.str();
132206084Srdivacky  DelayedDiagArg2 = Arg2.str();
133206084Srdivacky}
134206084Srdivacky
135226633Sdimvoid DiagnosticsEngine::ReportDelayed() {
136206084Srdivacky  Report(DelayedDiagID) << DelayedDiagArg1 << DelayedDiagArg2;
137206084Srdivacky  DelayedDiagID = 0;
138206084Srdivacky  DelayedDiagArg1.clear();
139206084Srdivacky  DelayedDiagArg2.clear();
140206084Srdivacky}
141206084Srdivacky
142226633SdimDiagnosticsEngine::DiagStatePointsTy::iterator
143226633SdimDiagnosticsEngine::GetDiagStatePointForLoc(SourceLocation L) const {
144218893Sdim  assert(!DiagStatePoints.empty());
145218893Sdim  assert(DiagStatePoints.front().Loc.isInvalid() &&
146218893Sdim         "Should have created a DiagStatePoint for command-line");
147198092Srdivacky
148239462Sdim  if (!SourceMgr)
149239462Sdim    return DiagStatePoints.end() - 1;
150239462Sdim
151218893Sdim  FullSourceLoc Loc(L, *SourceMgr);
152218893Sdim  if (Loc.isInvalid())
153218893Sdim    return DiagStatePoints.end() - 1;
154193326Sed
155218893Sdim  DiagStatePointsTy::iterator Pos = DiagStatePoints.end();
156218893Sdim  FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
157218893Sdim  if (LastStateChangePos.isValid() &&
158218893Sdim      Loc.isBeforeInTranslationUnitThan(LastStateChangePos))
159218893Sdim    Pos = std::upper_bound(DiagStatePoints.begin(), DiagStatePoints.end(),
160218893Sdim                           DiagStatePoint(0, Loc));
161218893Sdim  --Pos;
162218893Sdim  return Pos;
163193326Sed}
164193326Sed
165226633Sdimvoid DiagnosticsEngine::setDiagnosticMapping(diag::kind Diag, diag::Mapping Map,
166234353Sdim                                             SourceLocation L) {
167218893Sdim  assert(Diag < diag::DIAG_UPPER_LIMIT &&
168218893Sdim         "Can only map builtin diagnostics");
169218893Sdim  assert((Diags->isBuiltinWarningOrExtension(Diag) ||
170218893Sdim          (Map == diag::MAP_FATAL || Map == diag::MAP_ERROR)) &&
171218893Sdim         "Cannot map errors into warnings!");
172218893Sdim  assert(!DiagStatePoints.empty());
173239462Sdim  assert((L.isInvalid() || SourceMgr) && "No SourceMgr for valid location");
174193326Sed
175239462Sdim  FullSourceLoc Loc = SourceMgr? FullSourceLoc(L, *SourceMgr) : FullSourceLoc();
176218893Sdim  FullSourceLoc LastStateChangePos = DiagStatePoints.back().Loc;
177234353Sdim  // Don't allow a mapping to a warning override an error/fatal mapping.
178234353Sdim  if (Map == diag::MAP_WARNING) {
179234353Sdim    DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
180234353Sdim    if (Info.getMapping() == diag::MAP_ERROR ||
181234353Sdim        Info.getMapping() == diag::MAP_FATAL)
182234353Sdim      Map = Info.getMapping();
183226633Sdim  }
184234353Sdim  DiagnosticMappingInfo MappingInfo = makeMappingInfo(Map, L);
185226633Sdim
186218893Sdim  // Common case; setting all the diagnostics of a group in one place.
187218893Sdim  if (Loc.isInvalid() || Loc == LastStateChangePos) {
188226633Sdim    GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
189218893Sdim    return;
190193326Sed  }
191198092Srdivacky
192218893Sdim  // Another common case; modifying diagnostic state in a source location
193218893Sdim  // after the previous one.
194218893Sdim  if ((Loc.isValid() && LastStateChangePos.isInvalid()) ||
195218893Sdim      LastStateChangePos.isBeforeInTranslationUnitThan(Loc)) {
196221345Sdim    // A diagnostic pragma occurred, create a new DiagState initialized with
197218893Sdim    // the current one and a new DiagStatePoint to record at which location
198218893Sdim    // the new state became active.
199218893Sdim    DiagStates.push_back(*GetCurDiagState());
200218893Sdim    PushDiagStatePoint(&DiagStates.back(), Loc);
201226633Sdim    GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
202218893Sdim    return;
203193326Sed  }
204193326Sed
205218893Sdim  // We allow setting the diagnostic state in random source order for
206218893Sdim  // completeness but it should not be actually happening in normal practice.
207198092Srdivacky
208218893Sdim  DiagStatePointsTy::iterator Pos = GetDiagStatePointForLoc(Loc);
209218893Sdim  assert(Pos != DiagStatePoints.end());
210198092Srdivacky
211218893Sdim  // Update all diagnostic states that are active after the given location.
212218893Sdim  for (DiagStatePointsTy::iterator
213218893Sdim         I = Pos+1, E = DiagStatePoints.end(); I != E; ++I) {
214226633Sdim    GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
215193326Sed  }
216193326Sed
217218893Sdim  // If the location corresponds to an existing point, just update its state.
218218893Sdim  if (Pos->Loc == Loc) {
219226633Sdim    GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
220218893Sdim    return;
221198092Srdivacky  }
222193326Sed
223218893Sdim  // Create a new state/point and fit it into the vector of DiagStatePoints
224218893Sdim  // so that the vector is always ordered according to location.
225218893Sdim  Pos->Loc.isBeforeInTranslationUnitThan(Loc);
226218893Sdim  DiagStates.push_back(*Pos->State);
227218893Sdim  DiagState *NewState = &DiagStates.back();
228226633Sdim  GetCurDiagState()->setMappingInfo(Diag, MappingInfo);
229218893Sdim  DiagStatePoints.insert(Pos+1, DiagStatePoint(NewState,
230218893Sdim                                               FullSourceLoc(Loc, *SourceMgr)));
231218893Sdim}
232212904Sdim
233226633Sdimbool DiagnosticsEngine::setDiagnosticGroupMapping(
234226633Sdim  StringRef Group, diag::Mapping Map, SourceLocation Loc)
235226633Sdim{
236226633Sdim  // Get the diagnostics in this group.
237249423Sdim  SmallVector<diag::kind, 8> GroupDiags;
238226633Sdim  if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
239226633Sdim    return true;
240226633Sdim
241226633Sdim  // Set the mapping.
242226633Sdim  for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i)
243226633Sdim    setDiagnosticMapping(GroupDiags[i], Map, Loc);
244226633Sdim
245226633Sdim  return false;
246226633Sdim}
247226633Sdim
248234353Sdimvoid DiagnosticsEngine::setDiagnosticWarningAsError(diag::kind Diag,
249234353Sdim                                                    bool Enabled) {
250234353Sdim  // If we are enabling this feature, just set the diagnostic mappings to map to
251234353Sdim  // errors.
252234353Sdim  if (Enabled)
253234353Sdim    setDiagnosticMapping(Diag, diag::MAP_ERROR, SourceLocation());
254234353Sdim
255234353Sdim  // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
256234353Sdim  // potentially downgrade anything already mapped to be a warning.
257234353Sdim  DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
258234353Sdim
259234353Sdim  if (Info.getMapping() == diag::MAP_ERROR ||
260234353Sdim      Info.getMapping() == diag::MAP_FATAL)
261234353Sdim    Info.setMapping(diag::MAP_WARNING);
262234353Sdim
263234353Sdim  Info.setNoWarningAsError(true);
264234353Sdim}
265234353Sdim
266226633Sdimbool DiagnosticsEngine::setDiagnosticGroupWarningAsError(StringRef Group,
267226633Sdim                                                         bool Enabled) {
268226633Sdim  // If we are enabling this feature, just set the diagnostic mappings to map to
269226633Sdim  // errors.
270226633Sdim  if (Enabled)
271226633Sdim    return setDiagnosticGroupMapping(Group, diag::MAP_ERROR);
272226633Sdim
273226633Sdim  // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
274226633Sdim  // potentially downgrade anything already mapped to be a warning.
275226633Sdim
276226633Sdim  // Get the diagnostics in this group.
277249423Sdim  SmallVector<diag::kind, 8> GroupDiags;
278226633Sdim  if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
279226633Sdim    return true;
280226633Sdim
281226633Sdim  // Perform the mapping change.
282226633Sdim  for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
283226633Sdim    DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(
284226633Sdim      GroupDiags[i]);
285226633Sdim
286226633Sdim    if (Info.getMapping() == diag::MAP_ERROR ||
287226633Sdim        Info.getMapping() == diag::MAP_FATAL)
288226633Sdim      Info.setMapping(diag::MAP_WARNING);
289226633Sdim
290226633Sdim    Info.setNoWarningAsError(true);
291226633Sdim  }
292226633Sdim
293226633Sdim  return false;
294226633Sdim}
295226633Sdim
296234353Sdimvoid DiagnosticsEngine::setDiagnosticErrorAsFatal(diag::kind Diag,
297234353Sdim                                                  bool Enabled) {
298234353Sdim  // If we are enabling this feature, just set the diagnostic mappings to map to
299234353Sdim  // errors.
300234353Sdim  if (Enabled)
301234353Sdim    setDiagnosticMapping(Diag, diag::MAP_FATAL, SourceLocation());
302234353Sdim
303234353Sdim  // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
304234353Sdim  // potentially downgrade anything already mapped to be a warning.
305234353Sdim  DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(Diag);
306234353Sdim
307234353Sdim  if (Info.getMapping() == diag::MAP_FATAL)
308234353Sdim    Info.setMapping(diag::MAP_ERROR);
309234353Sdim
310234353Sdim  Info.setNoErrorAsFatal(true);
311234353Sdim}
312234353Sdim
313226633Sdimbool DiagnosticsEngine::setDiagnosticGroupErrorAsFatal(StringRef Group,
314226633Sdim                                                       bool Enabled) {
315226633Sdim  // If we are enabling this feature, just set the diagnostic mappings to map to
316226633Sdim  // fatal errors.
317226633Sdim  if (Enabled)
318226633Sdim    return setDiagnosticGroupMapping(Group, diag::MAP_FATAL);
319226633Sdim
320226633Sdim  // Otherwise, we want to set the diagnostic mapping's "no Werror" bit, and
321226633Sdim  // potentially downgrade anything already mapped to be an error.
322226633Sdim
323226633Sdim  // Get the diagnostics in this group.
324249423Sdim  SmallVector<diag::kind, 8> GroupDiags;
325226633Sdim  if (Diags->getDiagnosticsInGroup(Group, GroupDiags))
326226633Sdim    return true;
327226633Sdim
328226633Sdim  // Perform the mapping change.
329226633Sdim  for (unsigned i = 0, e = GroupDiags.size(); i != e; ++i) {
330226633Sdim    DiagnosticMappingInfo &Info = GetCurDiagState()->getOrAddMappingInfo(
331226633Sdim      GroupDiags[i]);
332226633Sdim
333226633Sdim    if (Info.getMapping() == diag::MAP_FATAL)
334226633Sdim      Info.setMapping(diag::MAP_ERROR);
335226633Sdim
336226633Sdim    Info.setNoErrorAsFatal(true);
337226633Sdim  }
338226633Sdim
339226633Sdim  return false;
340226633Sdim}
341226633Sdim
342234353Sdimvoid DiagnosticsEngine::setMappingToAllDiagnostics(diag::Mapping Map,
343234353Sdim                                                   SourceLocation Loc) {
344234353Sdim  // Get all the diagnostics.
345249423Sdim  SmallVector<diag::kind, 64> AllDiags;
346234353Sdim  Diags->getAllDiagnostics(AllDiags);
347234353Sdim
348234353Sdim  // Set the mapping.
349234353Sdim  for (unsigned i = 0, e = AllDiags.size(); i != e; ++i)
350234353Sdim    if (Diags->isBuiltinWarningOrExtension(AllDiags[i]))
351234353Sdim      setDiagnosticMapping(AllDiags[i], Map, Loc);
352234353Sdim}
353234353Sdim
354226633Sdimvoid DiagnosticsEngine::Report(const StoredDiagnostic &storedDiag) {
355223017Sdim  assert(CurDiagID == ~0U && "Multiple diagnostics in flight at once!");
356223017Sdim
357223017Sdim  CurDiagLoc = storedDiag.getLocation();
358223017Sdim  CurDiagID = storedDiag.getID();
359223017Sdim  NumDiagArgs = 0;
360223017Sdim
361223017Sdim  NumDiagRanges = storedDiag.range_size();
362234353Sdim  assert(NumDiagRanges < DiagnosticsEngine::MaxRanges &&
363223017Sdim         "Too many arguments to diagnostic!");
364223017Sdim  unsigned i = 0;
365223017Sdim  for (StoredDiagnostic::range_iterator
366223017Sdim         RI = storedDiag.range_begin(),
367223017Sdim         RE = storedDiag.range_end(); RI != RE; ++RI)
368223017Sdim    DiagRanges[i++] = *RI;
369223017Sdim
370234353Sdim  assert(NumDiagRanges < DiagnosticsEngine::MaxFixItHints &&
371234353Sdim         "Too many arguments to diagnostic!");
372234353Sdim  NumDiagFixItHints = 0;
373223017Sdim  for (StoredDiagnostic::fixit_iterator
374223017Sdim         FI = storedDiag.fixit_begin(),
375223017Sdim         FE = storedDiag.fixit_end(); FI != FE; ++FI)
376234353Sdim    DiagFixItHints[NumDiagFixItHints++] = *FI;
377223017Sdim
378226633Sdim  assert(Client && "DiagnosticConsumer not set!");
379223017Sdim  Level DiagLevel = storedDiag.getLevel();
380226633Sdim  Diagnostic Info(this, storedDiag.getMessage());
381223017Sdim  Client->HandleDiagnostic(DiagLevel, Info);
382223017Sdim  if (Client->IncludeInDiagnosticCounts()) {
383226633Sdim    if (DiagLevel == DiagnosticsEngine::Warning)
384223017Sdim      ++NumWarnings;
385223017Sdim  }
386223017Sdim
387223017Sdim  CurDiagID = ~0U;
388223017Sdim}
389223017Sdim
390239462Sdimbool DiagnosticsEngine::EmitCurrentDiagnostic(bool Force) {
391239462Sdim  assert(getClient() && "DiagnosticClient not set!");
392206084Srdivacky
393239462Sdim  bool Emitted;
394239462Sdim  if (Force) {
395239462Sdim    Diagnostic Info(this);
396239462Sdim
397239462Sdim    // Figure out the diagnostic level of this message.
398239462Sdim    DiagnosticIDs::Level DiagLevel
399239462Sdim      = Diags->getDiagnosticLevel(Info.getID(), Info.getLocation(), *this);
400239462Sdim
401239462Sdim    Emitted = (DiagLevel != DiagnosticIDs::Ignored);
402239462Sdim    if (Emitted) {
403239462Sdim      // Emit the diagnostic regardless of suppression level.
404239462Sdim      Diags->EmitDiag(*this, DiagLevel);
405239462Sdim    }
406239462Sdim  } else {
407239462Sdim    // Process the diagnostic, sending the accumulated information to the
408239462Sdim    // DiagnosticConsumer.
409239462Sdim    Emitted = ProcessDiag();
410239462Sdim  }
411239462Sdim
412206084Srdivacky  // Clear out the current diagnostic object.
413234353Sdim  unsigned DiagID = CurDiagID;
414234353Sdim  Clear();
415206084Srdivacky
416206084Srdivacky  // If there was a delayed diagnostic, emit it now.
417239462Sdim  if (!Force && DelayedDiagID && DelayedDiagID != DiagID)
418234353Sdim    ReportDelayed();
419206084Srdivacky
420206084Srdivacky  return Emitted;
421206084Srdivacky}
422206084Srdivacky
423206084Srdivacky
424226633SdimDiagnosticConsumer::~DiagnosticConsumer() {}
425193326Sed
426226633Sdimvoid DiagnosticConsumer::HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
427226633Sdim                                        const Diagnostic &Info) {
428218893Sdim  if (!IncludeInDiagnosticCounts())
429218893Sdim    return;
430193326Sed
431226633Sdim  if (DiagLevel == DiagnosticsEngine::Warning)
432218893Sdim    ++NumWarnings;
433226633Sdim  else if (DiagLevel >= DiagnosticsEngine::Error)
434218893Sdim    ++NumErrors;
435218893Sdim}
436218893Sdim
437193326Sed/// ModifierIs - Return true if the specified modifier matches specified string.
438193326Sedtemplate <std::size_t StrLen>
439193326Sedstatic bool ModifierIs(const char *Modifier, unsigned ModifierLen,
440193326Sed                       const char (&Str)[StrLen]) {
441193326Sed  return StrLen-1 == ModifierLen && !memcmp(Modifier, Str, StrLen-1);
442193326Sed}
443193326Sed
444202379Srdivacky/// ScanForward - Scans forward, looking for the given character, skipping
445202379Srdivacky/// nested clauses and escaped characters.
446202379Srdivackystatic const char *ScanFormat(const char *I, const char *E, char Target) {
447202379Srdivacky  unsigned Depth = 0;
448202379Srdivacky
449202379Srdivacky  for ( ; I != E; ++I) {
450202379Srdivacky    if (Depth == 0 && *I == Target) return I;
451202379Srdivacky    if (Depth != 0 && *I == '}') Depth--;
452202379Srdivacky
453202379Srdivacky    if (*I == '%') {
454202379Srdivacky      I++;
455202379Srdivacky      if (I == E) break;
456202379Srdivacky
457202379Srdivacky      // Escaped characters get implicitly skipped here.
458202379Srdivacky
459202379Srdivacky      // Format specifier.
460249423Sdim      if (!isDigit(*I) && !isPunctuation(*I)) {
461249423Sdim        for (I++; I != E && !isDigit(*I) && *I != '{'; I++) ;
462202379Srdivacky        if (I == E) break;
463202379Srdivacky        if (*I == '{')
464202379Srdivacky          Depth++;
465202379Srdivacky      }
466202379Srdivacky    }
467202379Srdivacky  }
468202379Srdivacky  return E;
469202379Srdivacky}
470202379Srdivacky
471193326Sed/// HandleSelectModifier - Handle the integer 'select' modifier.  This is used
472193326Sed/// like this:  %select{foo|bar|baz}2.  This means that the integer argument
473193326Sed/// "%2" has a value from 0-2.  If the value is 0, the diagnostic prints 'foo'.
474193326Sed/// If the value is 1, it prints 'bar'.  If it has the value 2, it prints 'baz'.
475193326Sed/// This is very useful for certain classes of variant diagnostics.
476226633Sdimstatic void HandleSelectModifier(const Diagnostic &DInfo, unsigned ValNo,
477193326Sed                                 const char *Argument, unsigned ArgumentLen,
478226633Sdim                                 SmallVectorImpl<char> &OutStr) {
479193326Sed  const char *ArgumentEnd = Argument+ArgumentLen;
480198092Srdivacky
481193326Sed  // Skip over 'ValNo' |'s.
482193326Sed  while (ValNo) {
483202379Srdivacky    const char *NextVal = ScanFormat(Argument, ArgumentEnd, '|');
484193326Sed    assert(NextVal != ArgumentEnd && "Value for integer select modifier was"
485193326Sed           " larger than the number of options in the diagnostic string!");
486193326Sed    Argument = NextVal+1;  // Skip this string.
487193326Sed    --ValNo;
488193326Sed  }
489198092Srdivacky
490193326Sed  // Get the end of the value.  This is either the } or the |.
491202379Srdivacky  const char *EndPtr = ScanFormat(Argument, ArgumentEnd, '|');
492202379Srdivacky
493202379Srdivacky  // Recursively format the result of the select clause into the output string.
494202379Srdivacky  DInfo.FormatDiagnostic(Argument, EndPtr, OutStr);
495193326Sed}
496193326Sed
497193326Sed/// HandleIntegerSModifier - Handle the integer 's' modifier.  This adds the
498193326Sed/// letter 's' to the string if the value is not 1.  This is used in cases like
499193326Sed/// this:  "you idiot, you have %4 parameter%s4!".
500193326Sedstatic void HandleIntegerSModifier(unsigned ValNo,
501226633Sdim                                   SmallVectorImpl<char> &OutStr) {
502193326Sed  if (ValNo != 1)
503193326Sed    OutStr.push_back('s');
504193326Sed}
505193326Sed
506202379Srdivacky/// HandleOrdinalModifier - Handle the integer 'ord' modifier.  This
507202379Srdivacky/// prints the ordinal form of the given integer, with 1 corresponding
508202379Srdivacky/// to the first ordinal.  Currently this is hard-coded to use the
509202379Srdivacky/// English form.
510202379Srdivackystatic void HandleOrdinalModifier(unsigned ValNo,
511226633Sdim                                  SmallVectorImpl<char> &OutStr) {
512202379Srdivacky  assert(ValNo != 0 && "ValNo must be strictly positive!");
513193326Sed
514202379Srdivacky  llvm::raw_svector_ostream Out(OutStr);
515202379Srdivacky
516202379Srdivacky  // We could use text forms for the first N ordinals, but the numeric
517202379Srdivacky  // forms are actually nicer in diagnostics because they stand out.
518243830Sdim  Out << ValNo << llvm::getOrdinalSuffix(ValNo);
519202379Srdivacky}
520202379Srdivacky
521202379Srdivacky
522193326Sed/// PluralNumber - Parse an unsigned integer and advance Start.
523193326Sedstatic unsigned PluralNumber(const char *&Start, const char *End) {
524193326Sed  // Programming 101: Parse a decimal number :-)
525193326Sed  unsigned Val = 0;
526193326Sed  while (Start != End && *Start >= '0' && *Start <= '9') {
527193326Sed    Val *= 10;
528193326Sed    Val += *Start - '0';
529193326Sed    ++Start;
530193326Sed  }
531193326Sed  return Val;
532193326Sed}
533193326Sed
534193326Sed/// TestPluralRange - Test if Val is in the parsed range. Modifies Start.
535193326Sedstatic bool TestPluralRange(unsigned Val, const char *&Start, const char *End) {
536193326Sed  if (*Start != '[') {
537193326Sed    unsigned Ref = PluralNumber(Start, End);
538193326Sed    return Ref == Val;
539193326Sed  }
540193326Sed
541193326Sed  ++Start;
542193326Sed  unsigned Low = PluralNumber(Start, End);
543193326Sed  assert(*Start == ',' && "Bad plural expression syntax: expected ,");
544193326Sed  ++Start;
545193326Sed  unsigned High = PluralNumber(Start, End);
546193326Sed  assert(*Start == ']' && "Bad plural expression syntax: expected )");
547193326Sed  ++Start;
548193326Sed  return Low <= Val && Val <= High;
549193326Sed}
550193326Sed
551193326Sed/// EvalPluralExpr - Actual expression evaluator for HandlePluralModifier.
552193326Sedstatic bool EvalPluralExpr(unsigned ValNo, const char *Start, const char *End) {
553193326Sed  // Empty condition?
554193326Sed  if (*Start == ':')
555193326Sed    return true;
556193326Sed
557193326Sed  while (1) {
558193326Sed    char C = *Start;
559193326Sed    if (C == '%') {
560193326Sed      // Modulo expression
561193326Sed      ++Start;
562193326Sed      unsigned Arg = PluralNumber(Start, End);
563193326Sed      assert(*Start == '=' && "Bad plural expression syntax: expected =");
564193326Sed      ++Start;
565193326Sed      unsigned ValMod = ValNo % Arg;
566193326Sed      if (TestPluralRange(ValMod, Start, End))
567193326Sed        return true;
568193326Sed    } else {
569193326Sed      assert((C == '[' || (C >= '0' && C <= '9')) &&
570193326Sed             "Bad plural expression syntax: unexpected character");
571193326Sed      // Range expression
572193326Sed      if (TestPluralRange(ValNo, Start, End))
573193326Sed        return true;
574193326Sed    }
575193326Sed
576193326Sed    // Scan for next or-expr part.
577193326Sed    Start = std::find(Start, End, ',');
578198092Srdivacky    if (Start == End)
579193326Sed      break;
580193326Sed    ++Start;
581193326Sed  }
582193326Sed  return false;
583193326Sed}
584193326Sed
585193326Sed/// HandlePluralModifier - Handle the integer 'plural' modifier. This is used
586193326Sed/// for complex plural forms, or in languages where all plurals are complex.
587193326Sed/// The syntax is: %plural{cond1:form1|cond2:form2|:form3}, where condn are
588193326Sed/// conditions that are tested in order, the form corresponding to the first
589193326Sed/// that applies being emitted. The empty condition is always true, making the
590193326Sed/// last form a default case.
591193326Sed/// Conditions are simple boolean expressions, where n is the number argument.
592193326Sed/// Here are the rules.
593193326Sed/// condition  := expression | empty
594193326Sed/// empty      :=                             -> always true
595193326Sed/// expression := numeric [',' expression]    -> logical or
596193326Sed/// numeric    := range                       -> true if n in range
597193326Sed///             | '%' number '=' range        -> true if n % number in range
598193326Sed/// range      := number
599193326Sed///             | '[' number ',' number ']'   -> ranges are inclusive both ends
600193326Sed///
601193326Sed/// Here are some examples from the GNU gettext manual written in this form:
602193326Sed/// English:
603193326Sed/// {1:form0|:form1}
604193326Sed/// Latvian:
605193326Sed/// {0:form2|%100=11,%10=0,%10=[2,9]:form1|:form0}
606193326Sed/// Gaeilge:
607193326Sed/// {1:form0|2:form1|:form2}
608193326Sed/// Romanian:
609193326Sed/// {1:form0|0,%100=[1,19]:form1|:form2}
610193326Sed/// Lithuanian:
611193326Sed/// {%10=0,%100=[10,19]:form2|%10=1:form0|:form1}
612193326Sed/// Russian (requires repeated form):
613193326Sed/// {%100=[11,14]:form2|%10=1:form0|%10=[2,4]:form1|:form2}
614193326Sed/// Slovak
615193326Sed/// {1:form0|[2,4]:form1|:form2}
616193326Sed/// Polish (requires repeated form):
617193326Sed/// {1:form0|%100=[10,20]:form2|%10=[2,4]:form1|:form2}
618226633Sdimstatic void HandlePluralModifier(const Diagnostic &DInfo, unsigned ValNo,
619193326Sed                                 const char *Argument, unsigned ArgumentLen,
620226633Sdim                                 SmallVectorImpl<char> &OutStr) {
621193326Sed  const char *ArgumentEnd = Argument + ArgumentLen;
622193326Sed  while (1) {
623193326Sed    assert(Argument < ArgumentEnd && "Plural expression didn't match.");
624193326Sed    const char *ExprEnd = Argument;
625193326Sed    while (*ExprEnd != ':') {
626193326Sed      assert(ExprEnd != ArgumentEnd && "Plural missing expression end");
627193326Sed      ++ExprEnd;
628193326Sed    }
629193326Sed    if (EvalPluralExpr(ValNo, Argument, ExprEnd)) {
630193326Sed      Argument = ExprEnd + 1;
631202379Srdivacky      ExprEnd = ScanFormat(Argument, ArgumentEnd, '|');
632218893Sdim
633218893Sdim      // Recursively format the result of the plural clause into the
634218893Sdim      // output string.
635218893Sdim      DInfo.FormatDiagnostic(Argument, ExprEnd, OutStr);
636193326Sed      return;
637193326Sed    }
638202379Srdivacky    Argument = ScanFormat(Argument, ArgumentEnd - 1, '|') + 1;
639193326Sed  }
640193326Sed}
641193326Sed
642193326Sed
643193326Sed/// FormatDiagnostic - Format this diagnostic into a string, substituting the
644193326Sed/// formal arguments into the %0 slots.  The result is appended onto the Str
645193326Sed/// array.
646226633Sdimvoid Diagnostic::
647226633SdimFormatDiagnostic(SmallVectorImpl<char> &OutStr) const {
648223017Sdim  if (!StoredDiagMessage.empty()) {
649223017Sdim    OutStr.append(StoredDiagMessage.begin(), StoredDiagMessage.end());
650223017Sdim    return;
651223017Sdim  }
652198092Srdivacky
653226633Sdim  StringRef Diag =
654223017Sdim    getDiags()->getDiagnosticIDs()->getDescription(getID());
655223017Sdim
656223017Sdim  FormatDiagnostic(Diag.begin(), Diag.end(), OutStr);
657202379Srdivacky}
658202379Srdivacky
659226633Sdimvoid Diagnostic::
660202379SrdivackyFormatDiagnostic(const char *DiagStr, const char *DiagEnd,
661226633Sdim                 SmallVectorImpl<char> &OutStr) const {
662202379Srdivacky
663198398Srdivacky  /// FormattedArgs - Keep track of all of the arguments formatted by
664198398Srdivacky  /// ConvertArgToString and pass them into subsequent calls to
665198398Srdivacky  /// ConvertArgToString, allowing the implementation to avoid redundancies in
666198398Srdivacky  /// obvious cases.
667226633Sdim  SmallVector<DiagnosticsEngine::ArgumentValue, 8> FormattedArgs;
668224145Sdim
669224145Sdim  /// QualTypeVals - Pass a vector of arrays so that QualType names can be
670224145Sdim  /// compared to see if more information is needed to be printed.
671226633Sdim  SmallVector<intptr_t, 2> QualTypeVals;
672239462Sdim  SmallVector<char, 64> Tree;
673239462Sdim
674224145Sdim  for (unsigned i = 0, e = getNumArgs(); i < e; ++i)
675226633Sdim    if (getArgKind(i) == DiagnosticsEngine::ak_qualtype)
676224145Sdim      QualTypeVals.push_back(getRawArg(i));
677224145Sdim
678193326Sed  while (DiagStr != DiagEnd) {
679193326Sed    if (DiagStr[0] != '%') {
680193326Sed      // Append non-%0 substrings to Str if we have one.
681193326Sed      const char *StrEnd = std::find(DiagStr, DiagEnd, '%');
682193326Sed      OutStr.append(DiagStr, StrEnd);
683193326Sed      DiagStr = StrEnd;
684193326Sed      continue;
685249423Sdim    } else if (isPunctuation(DiagStr[1])) {
686202379Srdivacky      OutStr.push_back(DiagStr[1]);  // %% -> %.
687193326Sed      DiagStr += 2;
688193326Sed      continue;
689193326Sed    }
690198092Srdivacky
691193326Sed    // Skip the %.
692193326Sed    ++DiagStr;
693198092Srdivacky
694193326Sed    // This must be a placeholder for a diagnostic argument.  The format for a
695193326Sed    // placeholder is one of "%0", "%modifier0", or "%modifier{arguments}0".
696193326Sed    // The digit is a number from 0-9 indicating which argument this comes from.
697193326Sed    // The modifier is a string of digits from the set [-a-z]+, arguments is a
698193326Sed    // brace enclosed string.
699193326Sed    const char *Modifier = 0, *Argument = 0;
700193326Sed    unsigned ModifierLen = 0, ArgumentLen = 0;
701198092Srdivacky
702193326Sed    // Check to see if we have a modifier.  If so eat it.
703249423Sdim    if (!isDigit(DiagStr[0])) {
704193326Sed      Modifier = DiagStr;
705193326Sed      while (DiagStr[0] == '-' ||
706193326Sed             (DiagStr[0] >= 'a' && DiagStr[0] <= 'z'))
707193326Sed        ++DiagStr;
708193326Sed      ModifierLen = DiagStr-Modifier;
709193326Sed
710193326Sed      // If we have an argument, get it next.
711193326Sed      if (DiagStr[0] == '{') {
712193326Sed        ++DiagStr; // Skip {.
713193326Sed        Argument = DiagStr;
714198092Srdivacky
715202379Srdivacky        DiagStr = ScanFormat(DiagStr, DiagEnd, '}');
716202379Srdivacky        assert(DiagStr != DiagEnd && "Mismatched {}'s in diagnostic string!");
717193326Sed        ArgumentLen = DiagStr-Argument;
718193326Sed        ++DiagStr;  // Skip }.
719193326Sed      }
720193326Sed    }
721198092Srdivacky
722249423Sdim    assert(isDigit(*DiagStr) && "Invalid format for argument in diagnostic");
723193326Sed    unsigned ArgNo = *DiagStr++ - '0';
724193326Sed
725239462Sdim    // Only used for type diffing.
726239462Sdim    unsigned ArgNo2 = ArgNo;
727239462Sdim
728226633Sdim    DiagnosticsEngine::ArgumentKind Kind = getArgKind(ArgNo);
729249423Sdim    if (ModifierIs(Modifier, ModifierLen, "diff")) {
730249423Sdim      assert(*DiagStr == ',' && isDigit(*(DiagStr + 1)) &&
731239462Sdim             "Invalid format for diff modifier");
732239462Sdim      ++DiagStr;  // Comma.
733239462Sdim      ArgNo2 = *DiagStr++ - '0';
734249423Sdim      DiagnosticsEngine::ArgumentKind Kind2 = getArgKind(ArgNo2);
735249423Sdim      if (Kind == DiagnosticsEngine::ak_qualtype &&
736249423Sdim          Kind2 == DiagnosticsEngine::ak_qualtype)
737249423Sdim        Kind = DiagnosticsEngine::ak_qualtype_pair;
738249423Sdim      else {
739249423Sdim        // %diff only supports QualTypes.  For other kinds of arguments,
740249423Sdim        // use the default printing.  For example, if the modifier is:
741249423Sdim        //   "%diff{compare $ to $|other text}1,2"
742249423Sdim        // treat it as:
743249423Sdim        //   "compare %1 to %2"
744249423Sdim        const char *Pipe = ScanFormat(Argument, Argument + ArgumentLen, '|');
745249423Sdim        const char *FirstDollar = ScanFormat(Argument, Pipe, '$');
746249423Sdim        const char *SecondDollar = ScanFormat(FirstDollar + 1, Pipe, '$');
747249423Sdim        const char ArgStr1[] = { '%', static_cast<char>('0' + ArgNo) };
748249423Sdim        const char ArgStr2[] = { '%', static_cast<char>('0' + ArgNo2) };
749249423Sdim        FormatDiagnostic(Argument, FirstDollar, OutStr);
750249423Sdim        FormatDiagnostic(ArgStr1, ArgStr1 + 2, OutStr);
751249423Sdim        FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
752249423Sdim        FormatDiagnostic(ArgStr2, ArgStr2 + 2, OutStr);
753249423Sdim        FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
754249423Sdim        continue;
755249423Sdim      }
756239462Sdim    }
757198398Srdivacky
758198398Srdivacky    switch (Kind) {
759193326Sed    // ---- STRINGS ----
760226633Sdim    case DiagnosticsEngine::ak_std_string: {
761193326Sed      const std::string &S = getArgStdStr(ArgNo);
762193326Sed      assert(ModifierLen == 0 && "No modifiers for strings yet");
763193326Sed      OutStr.append(S.begin(), S.end());
764193326Sed      break;
765193326Sed    }
766226633Sdim    case DiagnosticsEngine::ak_c_string: {
767193326Sed      const char *S = getArgCStr(ArgNo);
768193326Sed      assert(ModifierLen == 0 && "No modifiers for strings yet");
769193326Sed
770193326Sed      // Don't crash if get passed a null pointer by accident.
771193326Sed      if (!S)
772193326Sed        S = "(null)";
773198092Srdivacky
774193326Sed      OutStr.append(S, S + strlen(S));
775193326Sed      break;
776193326Sed    }
777193326Sed    // ---- INTEGERS ----
778226633Sdim    case DiagnosticsEngine::ak_sint: {
779193326Sed      int Val = getArgSInt(ArgNo);
780198092Srdivacky
781193326Sed      if (ModifierIs(Modifier, ModifierLen, "select")) {
782218893Sdim        HandleSelectModifier(*this, (unsigned)Val, Argument, ArgumentLen,
783218893Sdim                             OutStr);
784193326Sed      } else if (ModifierIs(Modifier, ModifierLen, "s")) {
785193326Sed        HandleIntegerSModifier(Val, OutStr);
786193326Sed      } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
787218893Sdim        HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
788218893Sdim                             OutStr);
789202379Srdivacky      } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
790202379Srdivacky        HandleOrdinalModifier((unsigned)Val, OutStr);
791193326Sed      } else {
792193326Sed        assert(ModifierLen == 0 && "Unknown integer modifier");
793198398Srdivacky        llvm::raw_svector_ostream(OutStr) << Val;
794193326Sed      }
795193326Sed      break;
796193326Sed    }
797226633Sdim    case DiagnosticsEngine::ak_uint: {
798193326Sed      unsigned Val = getArgUInt(ArgNo);
799198092Srdivacky
800193326Sed      if (ModifierIs(Modifier, ModifierLen, "select")) {
801202379Srdivacky        HandleSelectModifier(*this, Val, Argument, ArgumentLen, OutStr);
802193326Sed      } else if (ModifierIs(Modifier, ModifierLen, "s")) {
803193326Sed        HandleIntegerSModifier(Val, OutStr);
804193326Sed      } else if (ModifierIs(Modifier, ModifierLen, "plural")) {
805218893Sdim        HandlePluralModifier(*this, (unsigned)Val, Argument, ArgumentLen,
806218893Sdim                             OutStr);
807202379Srdivacky      } else if (ModifierIs(Modifier, ModifierLen, "ordinal")) {
808202379Srdivacky        HandleOrdinalModifier(Val, OutStr);
809193326Sed      } else {
810193326Sed        assert(ModifierLen == 0 && "Unknown integer modifier");
811198398Srdivacky        llvm::raw_svector_ostream(OutStr) << Val;
812193326Sed      }
813193326Sed      break;
814193326Sed    }
815193326Sed    // ---- NAMES and TYPES ----
816226633Sdim    case DiagnosticsEngine::ak_identifierinfo: {
817193326Sed      const IdentifierInfo *II = getArgIdentifier(ArgNo);
818193326Sed      assert(ModifierLen == 0 && "No modifiers for strings yet");
819193326Sed
820193326Sed      // Don't crash if get passed a null pointer by accident.
821193326Sed      if (!II) {
822193326Sed        const char *S = "(null)";
823193326Sed        OutStr.append(S, S + strlen(S));
824193326Sed        continue;
825193326Sed      }
826193326Sed
827198398Srdivacky      llvm::raw_svector_ostream(OutStr) << '\'' << II->getName() << '\'';
828193326Sed      break;
829193326Sed    }
830226633Sdim    case DiagnosticsEngine::ak_qualtype:
831226633Sdim    case DiagnosticsEngine::ak_declarationname:
832226633Sdim    case DiagnosticsEngine::ak_nameddecl:
833226633Sdim    case DiagnosticsEngine::ak_nestednamespec:
834226633Sdim    case DiagnosticsEngine::ak_declcontext:
835198398Srdivacky      getDiags()->ConvertArgToString(Kind, getRawArg(ArgNo),
836193326Sed                                     Modifier, ModifierLen,
837198398Srdivacky                                     Argument, ArgumentLen,
838198398Srdivacky                                     FormattedArgs.data(), FormattedArgs.size(),
839224145Sdim                                     OutStr, QualTypeVals);
840193326Sed      break;
841239462Sdim    case DiagnosticsEngine::ak_qualtype_pair:
842239462Sdim      // Create a struct with all the info needed for printing.
843239462Sdim      TemplateDiffTypes TDT;
844239462Sdim      TDT.FromType = getRawArg(ArgNo);
845239462Sdim      TDT.ToType = getRawArg(ArgNo2);
846239462Sdim      TDT.ElideType = getDiags()->ElideType;
847239462Sdim      TDT.ShowColors = getDiags()->ShowColors;
848239462Sdim      TDT.TemplateDiffUsed = false;
849239462Sdim      intptr_t val = reinterpret_cast<intptr_t>(&TDT);
850239462Sdim
851239462Sdim      const char *ArgumentEnd = Argument + ArgumentLen;
852239462Sdim      const char *Pipe = ScanFormat(Argument, ArgumentEnd, '|');
853239462Sdim
854239462Sdim      // Print the tree.  If this diagnostic already has a tree, skip the
855239462Sdim      // second tree.
856239462Sdim      if (getDiags()->PrintTemplateTree && Tree.empty()) {
857239462Sdim        TDT.PrintFromType = true;
858239462Sdim        TDT.PrintTree = true;
859239462Sdim        getDiags()->ConvertArgToString(Kind, val,
860239462Sdim                                       Modifier, ModifierLen,
861239462Sdim                                       Argument, ArgumentLen,
862239462Sdim                                       FormattedArgs.data(),
863239462Sdim                                       FormattedArgs.size(),
864239462Sdim                                       Tree, QualTypeVals);
865239462Sdim        // If there is no tree information, fall back to regular printing.
866239462Sdim        if (!Tree.empty()) {
867239462Sdim          FormatDiagnostic(Pipe + 1, ArgumentEnd, OutStr);
868239462Sdim          break;
869239462Sdim        }
870239462Sdim      }
871239462Sdim
872239462Sdim      // Non-tree printing, also the fall-back when tree printing fails.
873239462Sdim      // The fall-back is triggered when the types compared are not templates.
874239462Sdim      const char *FirstDollar = ScanFormat(Argument, ArgumentEnd, '$');
875239462Sdim      const char *SecondDollar = ScanFormat(FirstDollar + 1, ArgumentEnd, '$');
876239462Sdim
877239462Sdim      // Append before text
878239462Sdim      FormatDiagnostic(Argument, FirstDollar, OutStr);
879239462Sdim
880239462Sdim      // Append first type
881239462Sdim      TDT.PrintTree = false;
882239462Sdim      TDT.PrintFromType = true;
883239462Sdim      getDiags()->ConvertArgToString(Kind, val,
884239462Sdim                                     Modifier, ModifierLen,
885239462Sdim                                     Argument, ArgumentLen,
886239462Sdim                                     FormattedArgs.data(), FormattedArgs.size(),
887239462Sdim                                     OutStr, QualTypeVals);
888239462Sdim      if (!TDT.TemplateDiffUsed)
889239462Sdim        FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
890239462Sdim                                               TDT.FromType));
891239462Sdim
892239462Sdim      // Append middle text
893239462Sdim      FormatDiagnostic(FirstDollar + 1, SecondDollar, OutStr);
894239462Sdim
895239462Sdim      // Append second type
896239462Sdim      TDT.PrintFromType = false;
897239462Sdim      getDiags()->ConvertArgToString(Kind, val,
898239462Sdim                                     Modifier, ModifierLen,
899239462Sdim                                     Argument, ArgumentLen,
900239462Sdim                                     FormattedArgs.data(), FormattedArgs.size(),
901239462Sdim                                     OutStr, QualTypeVals);
902239462Sdim      if (!TDT.TemplateDiffUsed)
903239462Sdim        FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_qualtype,
904239462Sdim                                               TDT.ToType));
905239462Sdim
906239462Sdim      // Append end text
907239462Sdim      FormatDiagnostic(SecondDollar + 1, Pipe, OutStr);
908239462Sdim      break;
909193326Sed    }
910198398Srdivacky
911198398Srdivacky    // Remember this argument info for subsequent formatting operations.  Turn
912198398Srdivacky    // std::strings into a null terminated string to make it be the same case as
913198398Srdivacky    // all the other ones.
914239462Sdim    if (Kind == DiagnosticsEngine::ak_qualtype_pair)
915239462Sdim      continue;
916239462Sdim    else if (Kind != DiagnosticsEngine::ak_std_string)
917198398Srdivacky      FormattedArgs.push_back(std::make_pair(Kind, getRawArg(ArgNo)));
918198398Srdivacky    else
919226633Sdim      FormattedArgs.push_back(std::make_pair(DiagnosticsEngine::ak_c_string,
920198398Srdivacky                                        (intptr_t)getArgStdStr(ArgNo).c_str()));
921198398Srdivacky
922193326Sed  }
923239462Sdim
924239462Sdim  // Append the type tree to the end of the diagnostics.
925239462Sdim  OutStr.append(Tree.begin(), Tree.end());
926193326Sed}
927193326Sed
928204643SrdivackyStoredDiagnostic::StoredDiagnostic() { }
929204643Srdivacky
930226633SdimStoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
931226633Sdim                                   StringRef Message)
932218893Sdim  : ID(ID), Level(Level), Loc(), Message(Message) { }
933204643Srdivacky
934226633SdimStoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level,
935226633Sdim                                   const Diagnostic &Info)
936218893Sdim  : ID(Info.getID()), Level(Level)
937218893Sdim{
938218893Sdim  assert((Info.getLocation().isInvalid() || Info.hasSourceManager()) &&
939218893Sdim       "Valid source location without setting a source manager for diagnostic");
940218893Sdim  if (Info.getLocation().isValid())
941218893Sdim    Loc = FullSourceLoc(Info.getLocation(), Info.getSourceManager());
942234353Sdim  SmallString<64> Message;
943204643Srdivacky  Info.FormatDiagnostic(Message);
944204643Srdivacky  this->Message.assign(Message.begin(), Message.end());
945204643Srdivacky
946204643Srdivacky  Ranges.reserve(Info.getNumRanges());
947204643Srdivacky  for (unsigned I = 0, N = Info.getNumRanges(); I != N; ++I)
948204643Srdivacky    Ranges.push_back(Info.getRange(I));
949204643Srdivacky
950206084Srdivacky  FixIts.reserve(Info.getNumFixItHints());
951206084Srdivacky  for (unsigned I = 0, N = Info.getNumFixItHints(); I != N; ++I)
952206084Srdivacky    FixIts.push_back(Info.getFixItHint(I));
953204643Srdivacky}
954204643Srdivacky
955226633SdimStoredDiagnostic::StoredDiagnostic(DiagnosticsEngine::Level Level, unsigned ID,
956226633Sdim                                   StringRef Message, FullSourceLoc Loc,
957226633Sdim                                   ArrayRef<CharSourceRange> Ranges,
958249423Sdim                                   ArrayRef<FixItHint> FixIts)
959249423Sdim  : ID(ID), Level(Level), Loc(Loc), Message(Message),
960249423Sdim    Ranges(Ranges.begin(), Ranges.end()), FixIts(FixIts.begin(), FixIts.end())
961226633Sdim{
962226633Sdim}
963226633Sdim
964204643SrdivackyStoredDiagnostic::~StoredDiagnostic() { }
965204643Srdivacky
966193326Sed/// IncludeInDiagnosticCounts - This method (whose default implementation
967193326Sed///  returns true) indicates whether the diagnostics handled by this
968226633Sdim///  DiagnosticConsumer should be included in the number of diagnostics
969226633Sdim///  reported by DiagnosticsEngine.
970226633Sdimbool DiagnosticConsumer::IncludeInDiagnosticCounts() const { return true; }
971206084Srdivacky
972234353Sdimvoid IgnoringDiagConsumer::anchor() { }
973234353Sdim
974251662SdimForwardingDiagnosticConsumer::~ForwardingDiagnosticConsumer() {}
975251662Sdim
976251662Sdimvoid ForwardingDiagnosticConsumer::HandleDiagnostic(
977251662Sdim       DiagnosticsEngine::Level DiagLevel,
978251662Sdim       const Diagnostic &Info) {
979251662Sdim  Target.HandleDiagnostic(DiagLevel, Info);
980251662Sdim}
981251662Sdim
982251662Sdimvoid ForwardingDiagnosticConsumer::clear() {
983251662Sdim  DiagnosticConsumer::clear();
984251662Sdim  Target.clear();
985251662Sdim}
986251662Sdim
987251662Sdimbool ForwardingDiagnosticConsumer::IncludeInDiagnosticCounts() const {
988251662Sdim  return Target.IncludeInDiagnosticCounts();
989251662Sdim}
990251662Sdim
991206084SrdivackyPartialDiagnostic::StorageAllocator::StorageAllocator() {
992206084Srdivacky  for (unsigned I = 0; I != NumCached; ++I)
993206084Srdivacky    FreeList[I] = Cached + I;
994206084Srdivacky  NumFreeListEntries = NumCached;
995206084Srdivacky}
996206084Srdivacky
997206084SrdivackyPartialDiagnostic::StorageAllocator::~StorageAllocator() {
998234353Sdim  // Don't assert if we are in a CrashRecovery context, as this invariant may
999234353Sdim  // be invalidated during a crash.
1000234353Sdim  assert((NumFreeListEntries == NumCached ||
1001234353Sdim          llvm::CrashRecoveryContext::isRecoveringFromCrash()) &&
1002234353Sdim         "A partial is on the lamb");
1003206084Srdivacky}
1004