xref: /openbsd-src/gnu/llvm/clang/tools/libclang/CIndexDiagnostic.cpp (revision ec727ea710c91afd8ce4f788c5aaa8482b7b69b2)
1e5dd7070Spatrick //===- CIndexDiagnostic.cpp - Diagnostics C Interface ---------------------===//
2e5dd7070Spatrick //
3e5dd7070Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e5dd7070Spatrick // See https://llvm.org/LICENSE.txt for license information.
5e5dd7070Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6e5dd7070Spatrick //
7e5dd7070Spatrick //===----------------------------------------------------------------------===//
8e5dd7070Spatrick //
9e5dd7070Spatrick // Implements the diagnostic functions of the Clang C interface.
10e5dd7070Spatrick //
11e5dd7070Spatrick //===----------------------------------------------------------------------===//
12e5dd7070Spatrick 
13e5dd7070Spatrick #include "CIndexDiagnostic.h"
14e5dd7070Spatrick #include "CIndexer.h"
15e5dd7070Spatrick #include "CXTranslationUnit.h"
16e5dd7070Spatrick #include "CXSourceLocation.h"
17e5dd7070Spatrick #include "CXString.h"
18e5dd7070Spatrick 
19e5dd7070Spatrick #include "clang/Basic/DiagnosticOptions.h"
20e5dd7070Spatrick #include "clang/Frontend/ASTUnit.h"
21e5dd7070Spatrick #include "clang/Frontend/DiagnosticRenderer.h"
22e5dd7070Spatrick #include "llvm/ADT/SmallString.h"
23e5dd7070Spatrick #include "llvm/Support/raw_ostream.h"
24e5dd7070Spatrick 
25e5dd7070Spatrick using namespace clang;
26e5dd7070Spatrick using namespace clang::cxloc;
27e5dd7070Spatrick using namespace clang::cxdiag;
28e5dd7070Spatrick using namespace llvm;
29e5dd7070Spatrick 
~CXDiagnosticSetImpl()30e5dd7070Spatrick CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {}
31e5dd7070Spatrick 
32e5dd7070Spatrick void
appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D)33e5dd7070Spatrick CXDiagnosticSetImpl::appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D) {
34e5dd7070Spatrick   Diagnostics.push_back(std::move(D));
35e5dd7070Spatrick }
36e5dd7070Spatrick 
~CXDiagnosticImpl()37e5dd7070Spatrick CXDiagnosticImpl::~CXDiagnosticImpl() {}
38e5dd7070Spatrick 
39e5dd7070Spatrick namespace {
40e5dd7070Spatrick class CXDiagnosticCustomNoteImpl : public CXDiagnosticImpl {
41e5dd7070Spatrick   std::string Message;
42e5dd7070Spatrick   CXSourceLocation Loc;
43e5dd7070Spatrick public:
CXDiagnosticCustomNoteImpl(StringRef Msg,CXSourceLocation L)44e5dd7070Spatrick   CXDiagnosticCustomNoteImpl(StringRef Msg, CXSourceLocation L)
45*ec727ea7Spatrick       : CXDiagnosticImpl(CustomNoteDiagnosticKind), Message(std::string(Msg)),
46*ec727ea7Spatrick         Loc(L) {}
47e5dd7070Spatrick 
~CXDiagnosticCustomNoteImpl()48e5dd7070Spatrick   ~CXDiagnosticCustomNoteImpl() override {}
49e5dd7070Spatrick 
getSeverity() const50e5dd7070Spatrick   CXDiagnosticSeverity getSeverity() const override {
51e5dd7070Spatrick     return CXDiagnostic_Note;
52e5dd7070Spatrick   }
53e5dd7070Spatrick 
getLocation() const54*ec727ea7Spatrick   CXSourceLocation getLocation() const override { return Loc; }
55e5dd7070Spatrick 
getSpelling() const56e5dd7070Spatrick   CXString getSpelling() const override {
57e5dd7070Spatrick     return cxstring::createRef(Message.c_str());
58e5dd7070Spatrick   }
59e5dd7070Spatrick 
getDiagnosticOption(CXString * Disable) const60e5dd7070Spatrick   CXString getDiagnosticOption(CXString *Disable) const override {
61e5dd7070Spatrick     if (Disable)
62e5dd7070Spatrick       *Disable = cxstring::createEmpty();
63e5dd7070Spatrick     return cxstring::createEmpty();
64e5dd7070Spatrick   }
65e5dd7070Spatrick 
getCategory() const66e5dd7070Spatrick   unsigned getCategory() const override { return 0; }
getCategoryText() const67e5dd7070Spatrick   CXString getCategoryText() const override { return cxstring::createEmpty(); }
68e5dd7070Spatrick 
getNumRanges() const69e5dd7070Spatrick   unsigned getNumRanges() const override { return 0; }
getRange(unsigned Range) const70e5dd7070Spatrick   CXSourceRange getRange(unsigned Range) const override {
71e5dd7070Spatrick     return clang_getNullRange();
72e5dd7070Spatrick   }
getNumFixIts() const73e5dd7070Spatrick   unsigned getNumFixIts() const override { return 0; }
getFixIt(unsigned FixIt,CXSourceRange * ReplacementRange) const74e5dd7070Spatrick   CXString getFixIt(unsigned FixIt,
75e5dd7070Spatrick                     CXSourceRange *ReplacementRange) const override {
76e5dd7070Spatrick     if (ReplacementRange)
77e5dd7070Spatrick       *ReplacementRange = clang_getNullRange();
78e5dd7070Spatrick     return cxstring::createEmpty();
79e5dd7070Spatrick   }
80e5dd7070Spatrick };
81e5dd7070Spatrick 
82e5dd7070Spatrick class CXDiagnosticRenderer : public DiagnosticNoteRenderer {
83e5dd7070Spatrick public:
CXDiagnosticRenderer(const LangOptions & LangOpts,DiagnosticOptions * DiagOpts,CXDiagnosticSetImpl * mainSet)84e5dd7070Spatrick   CXDiagnosticRenderer(const LangOptions &LangOpts,
85e5dd7070Spatrick                        DiagnosticOptions *DiagOpts,
86e5dd7070Spatrick                        CXDiagnosticSetImpl *mainSet)
87e5dd7070Spatrick   : DiagnosticNoteRenderer(LangOpts, DiagOpts),
88e5dd7070Spatrick     CurrentSet(mainSet), MainSet(mainSet) {}
89e5dd7070Spatrick 
~CXDiagnosticRenderer()90e5dd7070Spatrick   ~CXDiagnosticRenderer() override {}
91e5dd7070Spatrick 
beginDiagnostic(DiagOrStoredDiag D,DiagnosticsEngine::Level Level)92e5dd7070Spatrick   void beginDiagnostic(DiagOrStoredDiag D,
93e5dd7070Spatrick                        DiagnosticsEngine::Level Level) override {
94e5dd7070Spatrick 
95e5dd7070Spatrick     const StoredDiagnostic *SD = D.dyn_cast<const StoredDiagnostic*>();
96e5dd7070Spatrick     if (!SD)
97e5dd7070Spatrick       return;
98e5dd7070Spatrick 
99e5dd7070Spatrick     if (Level != DiagnosticsEngine::Note)
100e5dd7070Spatrick       CurrentSet = MainSet;
101e5dd7070Spatrick 
102e5dd7070Spatrick     auto Owner = std::make_unique<CXStoredDiagnostic>(*SD, LangOpts);
103e5dd7070Spatrick     CXStoredDiagnostic &CD = *Owner;
104e5dd7070Spatrick     CurrentSet->appendDiagnostic(std::move(Owner));
105e5dd7070Spatrick 
106e5dd7070Spatrick     if (Level != DiagnosticsEngine::Note)
107e5dd7070Spatrick       CurrentSet = &CD.getChildDiagnostics();
108e5dd7070Spatrick   }
109e5dd7070Spatrick 
emitDiagnosticMessage(FullSourceLoc Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,StringRef Message,ArrayRef<CharSourceRange> Ranges,DiagOrStoredDiag D)110e5dd7070Spatrick   void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
111e5dd7070Spatrick                              DiagnosticsEngine::Level Level, StringRef Message,
112e5dd7070Spatrick                              ArrayRef<CharSourceRange> Ranges,
113e5dd7070Spatrick                              DiagOrStoredDiag D) override {
114e5dd7070Spatrick     if (!D.isNull())
115e5dd7070Spatrick       return;
116e5dd7070Spatrick 
117e5dd7070Spatrick     CXSourceLocation L;
118e5dd7070Spatrick     if (Loc.hasManager())
119e5dd7070Spatrick       L = translateSourceLocation(Loc.getManager(), LangOpts, Loc);
120e5dd7070Spatrick     else
121e5dd7070Spatrick       L = clang_getNullLocation();
122e5dd7070Spatrick     CurrentSet->appendDiagnostic(
123e5dd7070Spatrick         std::make_unique<CXDiagnosticCustomNoteImpl>(Message, L));
124e5dd7070Spatrick   }
125e5dd7070Spatrick 
emitDiagnosticLoc(FullSourceLoc Loc,PresumedLoc PLoc,DiagnosticsEngine::Level Level,ArrayRef<CharSourceRange> Ranges)126e5dd7070Spatrick   void emitDiagnosticLoc(FullSourceLoc Loc, PresumedLoc PLoc,
127e5dd7070Spatrick                          DiagnosticsEngine::Level Level,
128e5dd7070Spatrick                          ArrayRef<CharSourceRange> Ranges) override {}
129e5dd7070Spatrick 
emitCodeContext(FullSourceLoc Loc,DiagnosticsEngine::Level Level,SmallVectorImpl<CharSourceRange> & Ranges,ArrayRef<FixItHint> Hints)130e5dd7070Spatrick   void emitCodeContext(FullSourceLoc Loc, DiagnosticsEngine::Level Level,
131e5dd7070Spatrick                        SmallVectorImpl<CharSourceRange> &Ranges,
132e5dd7070Spatrick                        ArrayRef<FixItHint> Hints) override {}
133e5dd7070Spatrick 
emitNote(FullSourceLoc Loc,StringRef Message)134e5dd7070Spatrick   void emitNote(FullSourceLoc Loc, StringRef Message) override {
135e5dd7070Spatrick     CXSourceLocation L;
136e5dd7070Spatrick     if (Loc.hasManager())
137e5dd7070Spatrick       L = translateSourceLocation(Loc.getManager(), LangOpts, Loc);
138e5dd7070Spatrick     else
139e5dd7070Spatrick       L = clang_getNullLocation();
140e5dd7070Spatrick     CurrentSet->appendDiagnostic(
141e5dd7070Spatrick         std::make_unique<CXDiagnosticCustomNoteImpl>(Message, L));
142e5dd7070Spatrick   }
143e5dd7070Spatrick 
144e5dd7070Spatrick   CXDiagnosticSetImpl *CurrentSet;
145e5dd7070Spatrick   CXDiagnosticSetImpl *MainSet;
146e5dd7070Spatrick };
147e5dd7070Spatrick }
148e5dd7070Spatrick 
lazyCreateDiags(CXTranslationUnit TU,bool checkIfChanged)149e5dd7070Spatrick CXDiagnosticSetImpl *cxdiag::lazyCreateDiags(CXTranslationUnit TU,
150e5dd7070Spatrick                                              bool checkIfChanged) {
151e5dd7070Spatrick   ASTUnit *AU = cxtu::getASTUnit(TU);
152e5dd7070Spatrick 
153e5dd7070Spatrick   if (TU->Diagnostics && checkIfChanged) {
154e5dd7070Spatrick     // In normal use, ASTUnit's diagnostics should not change unless we reparse.
155e5dd7070Spatrick     // Currently they can only change by using the internal testing flag
156e5dd7070Spatrick     // '-error-on-deserialized-decl' which will error during deserialization of
157e5dd7070Spatrick     // a declaration. What will happen is:
158e5dd7070Spatrick     //
159e5dd7070Spatrick     //  -c-index-test gets a CXTranslationUnit
160e5dd7070Spatrick     //  -checks the diagnostics, the diagnostics set is lazily created,
161e5dd7070Spatrick     //     no errors are reported
162e5dd7070Spatrick     //  -later does an operation, like annotation of tokens, that triggers
163e5dd7070Spatrick     //     -error-on-deserialized-decl, that will emit a diagnostic error,
164e5dd7070Spatrick     //     that ASTUnit will catch and add to its stored diagnostics vector.
165e5dd7070Spatrick     //  -c-index-test wants to check whether an error occurred after performing
166e5dd7070Spatrick     //     the operation but can only query the lazily created set.
167e5dd7070Spatrick     //
168e5dd7070Spatrick     // We check here if a new diagnostic was appended since the last time the
169e5dd7070Spatrick     // diagnostic set was created, in which case we reset it.
170e5dd7070Spatrick 
171e5dd7070Spatrick     CXDiagnosticSetImpl *
172e5dd7070Spatrick       Set = static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
173e5dd7070Spatrick     if (AU->stored_diag_size() != Set->getNumDiagnostics()) {
174e5dd7070Spatrick       // Diagnostics in the ASTUnit were updated, reset the associated
175e5dd7070Spatrick       // diagnostics.
176e5dd7070Spatrick       delete Set;
177e5dd7070Spatrick       TU->Diagnostics = nullptr;
178e5dd7070Spatrick     }
179e5dd7070Spatrick   }
180e5dd7070Spatrick 
181e5dd7070Spatrick   if (!TU->Diagnostics) {
182e5dd7070Spatrick     CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
183e5dd7070Spatrick     TU->Diagnostics = Set;
184e5dd7070Spatrick     IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
185e5dd7070Spatrick     CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
186e5dd7070Spatrick                                   &*DOpts, Set);
187e5dd7070Spatrick 
188e5dd7070Spatrick     for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
189e5dd7070Spatrick          ei = AU->stored_diag_end(); it != ei; ++it) {
190e5dd7070Spatrick       Renderer.emitStoredDiagnostic(*it);
191e5dd7070Spatrick     }
192e5dd7070Spatrick   }
193e5dd7070Spatrick   return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
194e5dd7070Spatrick }
195e5dd7070Spatrick 
196e5dd7070Spatrick //-----------------------------------------------------------------------------
197e5dd7070Spatrick // C Interface Routines
198e5dd7070Spatrick //-----------------------------------------------------------------------------
clang_getNumDiagnostics(CXTranslationUnit Unit)199e5dd7070Spatrick unsigned clang_getNumDiagnostics(CXTranslationUnit Unit) {
200e5dd7070Spatrick   if (cxtu::isNotUsableTU(Unit)) {
201e5dd7070Spatrick     LOG_BAD_TU(Unit);
202e5dd7070Spatrick     return 0;
203e5dd7070Spatrick   }
204e5dd7070Spatrick   if (!cxtu::getASTUnit(Unit))
205e5dd7070Spatrick     return 0;
206e5dd7070Spatrick   return lazyCreateDiags(Unit, /*checkIfChanged=*/true)->getNumDiagnostics();
207e5dd7070Spatrick }
208e5dd7070Spatrick 
clang_getDiagnostic(CXTranslationUnit Unit,unsigned Index)209e5dd7070Spatrick CXDiagnostic clang_getDiagnostic(CXTranslationUnit Unit, unsigned Index) {
210e5dd7070Spatrick   if (cxtu::isNotUsableTU(Unit)) {
211e5dd7070Spatrick     LOG_BAD_TU(Unit);
212e5dd7070Spatrick     return nullptr;
213e5dd7070Spatrick   }
214e5dd7070Spatrick 
215e5dd7070Spatrick   CXDiagnosticSet D = clang_getDiagnosticSetFromTU(Unit);
216e5dd7070Spatrick   if (!D)
217e5dd7070Spatrick     return nullptr;
218e5dd7070Spatrick 
219e5dd7070Spatrick   CXDiagnosticSetImpl *Diags = static_cast<CXDiagnosticSetImpl*>(D);
220e5dd7070Spatrick   if (Index >= Diags->getNumDiagnostics())
221e5dd7070Spatrick     return nullptr;
222e5dd7070Spatrick 
223e5dd7070Spatrick   return Diags->getDiagnostic(Index);
224e5dd7070Spatrick }
225e5dd7070Spatrick 
clang_getDiagnosticSetFromTU(CXTranslationUnit Unit)226e5dd7070Spatrick CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) {
227e5dd7070Spatrick   if (cxtu::isNotUsableTU(Unit)) {
228e5dd7070Spatrick     LOG_BAD_TU(Unit);
229e5dd7070Spatrick     return nullptr;
230e5dd7070Spatrick   }
231e5dd7070Spatrick   if (!cxtu::getASTUnit(Unit))
232e5dd7070Spatrick     return nullptr;
233e5dd7070Spatrick   return static_cast<CXDiagnostic>(lazyCreateDiags(Unit));
234e5dd7070Spatrick }
235e5dd7070Spatrick 
clang_disposeDiagnostic(CXDiagnostic Diagnostic)236e5dd7070Spatrick void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
237e5dd7070Spatrick   // No-op.  Kept as a legacy API.  CXDiagnostics are now managed
238e5dd7070Spatrick   // by the enclosing CXDiagnosticSet.
239e5dd7070Spatrick }
240e5dd7070Spatrick 
clang_formatDiagnostic(CXDiagnostic Diagnostic,unsigned Options)241e5dd7070Spatrick CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
242e5dd7070Spatrick   if (!Diagnostic)
243e5dd7070Spatrick     return cxstring::createEmpty();
244e5dd7070Spatrick 
245e5dd7070Spatrick   CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
246e5dd7070Spatrick 
247e5dd7070Spatrick   SmallString<256> Str;
248e5dd7070Spatrick   llvm::raw_svector_ostream Out(Str);
249e5dd7070Spatrick 
250e5dd7070Spatrick   if (Options & CXDiagnostic_DisplaySourceLocation) {
251e5dd7070Spatrick     // Print source location (file:line), along with optional column
252e5dd7070Spatrick     // and source ranges.
253e5dd7070Spatrick     CXFile File;
254e5dd7070Spatrick     unsigned Line, Column;
255e5dd7070Spatrick     clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
256e5dd7070Spatrick                               &File, &Line, &Column, nullptr);
257e5dd7070Spatrick     if (File) {
258e5dd7070Spatrick       CXString FName = clang_getFileName(File);
259e5dd7070Spatrick       Out << clang_getCString(FName) << ":" << Line << ":";
260e5dd7070Spatrick       clang_disposeString(FName);
261e5dd7070Spatrick       if (Options & CXDiagnostic_DisplayColumn)
262e5dd7070Spatrick         Out << Column << ":";
263e5dd7070Spatrick 
264e5dd7070Spatrick       if (Options & CXDiagnostic_DisplaySourceRanges) {
265e5dd7070Spatrick         unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
266e5dd7070Spatrick         bool PrintedRange = false;
267e5dd7070Spatrick         for (unsigned I = 0; I != N; ++I) {
268e5dd7070Spatrick           CXFile StartFile, EndFile;
269e5dd7070Spatrick           CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
270e5dd7070Spatrick 
271e5dd7070Spatrick           unsigned StartLine, StartColumn, EndLine, EndColumn;
272e5dd7070Spatrick           clang_getSpellingLocation(clang_getRangeStart(Range),
273e5dd7070Spatrick                                     &StartFile, &StartLine, &StartColumn,
274e5dd7070Spatrick                                     nullptr);
275e5dd7070Spatrick           clang_getSpellingLocation(clang_getRangeEnd(Range),
276e5dd7070Spatrick                                     &EndFile, &EndLine, &EndColumn, nullptr);
277e5dd7070Spatrick 
278e5dd7070Spatrick           if (StartFile != EndFile || StartFile != File)
279e5dd7070Spatrick             continue;
280e5dd7070Spatrick 
281e5dd7070Spatrick           Out << "{" << StartLine << ":" << StartColumn << "-"
282e5dd7070Spatrick               << EndLine << ":" << EndColumn << "}";
283e5dd7070Spatrick           PrintedRange = true;
284e5dd7070Spatrick         }
285e5dd7070Spatrick         if (PrintedRange)
286e5dd7070Spatrick           Out << ":";
287e5dd7070Spatrick       }
288e5dd7070Spatrick 
289e5dd7070Spatrick       Out << " ";
290e5dd7070Spatrick     }
291e5dd7070Spatrick   }
292e5dd7070Spatrick 
293e5dd7070Spatrick   /* Print warning/error/etc. */
294e5dd7070Spatrick   switch (Severity) {
295e5dd7070Spatrick   case CXDiagnostic_Ignored: llvm_unreachable("impossible");
296e5dd7070Spatrick   case CXDiagnostic_Note: Out << "note: "; break;
297e5dd7070Spatrick   case CXDiagnostic_Warning: Out << "warning: "; break;
298e5dd7070Spatrick   case CXDiagnostic_Error: Out << "error: "; break;
299e5dd7070Spatrick   case CXDiagnostic_Fatal: Out << "fatal error: "; break;
300e5dd7070Spatrick   }
301e5dd7070Spatrick 
302e5dd7070Spatrick   CXString Text = clang_getDiagnosticSpelling(Diagnostic);
303e5dd7070Spatrick   if (clang_getCString(Text))
304e5dd7070Spatrick     Out << clang_getCString(Text);
305e5dd7070Spatrick   else
306e5dd7070Spatrick     Out << "<no diagnostic text>";
307e5dd7070Spatrick   clang_disposeString(Text);
308e5dd7070Spatrick 
309e5dd7070Spatrick   if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |
310e5dd7070Spatrick                  CXDiagnostic_DisplayCategoryName)) {
311e5dd7070Spatrick     bool NeedBracket = true;
312e5dd7070Spatrick     bool NeedComma = false;
313e5dd7070Spatrick 
314e5dd7070Spatrick     if (Options & CXDiagnostic_DisplayOption) {
315e5dd7070Spatrick       CXString OptionName = clang_getDiagnosticOption(Diagnostic, nullptr);
316e5dd7070Spatrick       if (const char *OptionText = clang_getCString(OptionName)) {
317e5dd7070Spatrick         if (OptionText[0]) {
318e5dd7070Spatrick           Out << " [" << OptionText;
319e5dd7070Spatrick           NeedBracket = false;
320e5dd7070Spatrick           NeedComma = true;
321e5dd7070Spatrick         }
322e5dd7070Spatrick       }
323e5dd7070Spatrick       clang_disposeString(OptionName);
324e5dd7070Spatrick     }
325e5dd7070Spatrick 
326e5dd7070Spatrick     if (Options & (CXDiagnostic_DisplayCategoryId |
327e5dd7070Spatrick                    CXDiagnostic_DisplayCategoryName)) {
328e5dd7070Spatrick       if (unsigned CategoryID = clang_getDiagnosticCategory(Diagnostic)) {
329e5dd7070Spatrick         if (Options & CXDiagnostic_DisplayCategoryId) {
330e5dd7070Spatrick           if (NeedBracket)
331e5dd7070Spatrick             Out << " [";
332e5dd7070Spatrick           if (NeedComma)
333e5dd7070Spatrick             Out << ", ";
334e5dd7070Spatrick           Out << CategoryID;
335e5dd7070Spatrick           NeedBracket = false;
336e5dd7070Spatrick           NeedComma = true;
337e5dd7070Spatrick         }
338e5dd7070Spatrick 
339e5dd7070Spatrick         if (Options & CXDiagnostic_DisplayCategoryName) {
340e5dd7070Spatrick           CXString CategoryName = clang_getDiagnosticCategoryText(Diagnostic);
341e5dd7070Spatrick           if (NeedBracket)
342e5dd7070Spatrick             Out << " [";
343e5dd7070Spatrick           if (NeedComma)
344e5dd7070Spatrick             Out << ", ";
345e5dd7070Spatrick           Out << clang_getCString(CategoryName);
346e5dd7070Spatrick           NeedBracket = false;
347e5dd7070Spatrick           NeedComma = true;
348e5dd7070Spatrick           clang_disposeString(CategoryName);
349e5dd7070Spatrick         }
350e5dd7070Spatrick       }
351e5dd7070Spatrick     }
352e5dd7070Spatrick 
353e5dd7070Spatrick     (void) NeedComma; // Silence dead store warning.
354e5dd7070Spatrick     if (!NeedBracket)
355e5dd7070Spatrick       Out << "]";
356e5dd7070Spatrick   }
357e5dd7070Spatrick 
358e5dd7070Spatrick   return cxstring::createDup(Out.str());
359e5dd7070Spatrick }
360e5dd7070Spatrick 
clang_defaultDiagnosticDisplayOptions()361e5dd7070Spatrick unsigned clang_defaultDiagnosticDisplayOptions() {
362e5dd7070Spatrick   return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
363e5dd7070Spatrick          CXDiagnostic_DisplayOption;
364e5dd7070Spatrick }
365e5dd7070Spatrick 
clang_getDiagnosticSeverity(CXDiagnostic Diag)366e5dd7070Spatrick enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
367e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
368e5dd7070Spatrick     return D->getSeverity();
369e5dd7070Spatrick   return CXDiagnostic_Ignored;
370e5dd7070Spatrick }
371e5dd7070Spatrick 
clang_getDiagnosticLocation(CXDiagnostic Diag)372e5dd7070Spatrick CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
373e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
374e5dd7070Spatrick     return D->getLocation();
375e5dd7070Spatrick   return clang_getNullLocation();
376e5dd7070Spatrick }
377e5dd7070Spatrick 
clang_getDiagnosticSpelling(CXDiagnostic Diag)378e5dd7070Spatrick CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
379e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
380e5dd7070Spatrick     return D->getSpelling();
381e5dd7070Spatrick   return cxstring::createEmpty();
382e5dd7070Spatrick }
383e5dd7070Spatrick 
clang_getDiagnosticOption(CXDiagnostic Diag,CXString * Disable)384e5dd7070Spatrick CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
385e5dd7070Spatrick   if (Disable)
386e5dd7070Spatrick     *Disable = cxstring::createEmpty();
387e5dd7070Spatrick 
388e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
389e5dd7070Spatrick     return D->getDiagnosticOption(Disable);
390e5dd7070Spatrick 
391e5dd7070Spatrick   return cxstring::createEmpty();
392e5dd7070Spatrick }
393e5dd7070Spatrick 
clang_getDiagnosticCategory(CXDiagnostic Diag)394e5dd7070Spatrick unsigned clang_getDiagnosticCategory(CXDiagnostic Diag) {
395e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
396e5dd7070Spatrick     return D->getCategory();
397e5dd7070Spatrick   return 0;
398e5dd7070Spatrick }
399e5dd7070Spatrick 
clang_getDiagnosticCategoryName(unsigned Category)400e5dd7070Spatrick CXString clang_getDiagnosticCategoryName(unsigned Category) {
401e5dd7070Spatrick   // Kept for backward compatibility.
402e5dd7070Spatrick   return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(Category));
403e5dd7070Spatrick }
404e5dd7070Spatrick 
clang_getDiagnosticCategoryText(CXDiagnostic Diag)405e5dd7070Spatrick CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {
406e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
407e5dd7070Spatrick     return D->getCategoryText();
408e5dd7070Spatrick   return cxstring::createEmpty();
409e5dd7070Spatrick }
410e5dd7070Spatrick 
clang_getDiagnosticNumRanges(CXDiagnostic Diag)411e5dd7070Spatrick unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
412e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
413e5dd7070Spatrick     return D->getNumRanges();
414e5dd7070Spatrick   return 0;
415e5dd7070Spatrick }
416e5dd7070Spatrick 
clang_getDiagnosticRange(CXDiagnostic Diag,unsigned Range)417e5dd7070Spatrick CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
418e5dd7070Spatrick   CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
419e5dd7070Spatrick   if (!D || Range >= D->getNumRanges())
420e5dd7070Spatrick     return clang_getNullRange();
421e5dd7070Spatrick   return D->getRange(Range);
422e5dd7070Spatrick }
423e5dd7070Spatrick 
clang_getDiagnosticNumFixIts(CXDiagnostic Diag)424e5dd7070Spatrick unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
425e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
426e5dd7070Spatrick     return D->getNumFixIts();
427e5dd7070Spatrick   return 0;
428e5dd7070Spatrick }
429e5dd7070Spatrick 
clang_getDiagnosticFixIt(CXDiagnostic Diag,unsigned FixIt,CXSourceRange * ReplacementRange)430e5dd7070Spatrick CXString clang_getDiagnosticFixIt(CXDiagnostic Diag, unsigned FixIt,
431e5dd7070Spatrick                                   CXSourceRange *ReplacementRange) {
432e5dd7070Spatrick   CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);
433e5dd7070Spatrick   if (!D || FixIt >= D->getNumFixIts()) {
434e5dd7070Spatrick     if (ReplacementRange)
435e5dd7070Spatrick       *ReplacementRange = clang_getNullRange();
436e5dd7070Spatrick     return cxstring::createEmpty();
437e5dd7070Spatrick   }
438e5dd7070Spatrick   return D->getFixIt(FixIt, ReplacementRange);
439e5dd7070Spatrick }
440e5dd7070Spatrick 
clang_disposeDiagnosticSet(CXDiagnosticSet Diags)441e5dd7070Spatrick void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
442e5dd7070Spatrick   if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(Diags)) {
443e5dd7070Spatrick     if (D->isExternallyManaged())
444e5dd7070Spatrick       delete D;
445e5dd7070Spatrick   }
446e5dd7070Spatrick }
447e5dd7070Spatrick 
clang_getDiagnosticInSet(CXDiagnosticSet Diags,unsigned Index)448e5dd7070Spatrick CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
449e5dd7070Spatrick                                       unsigned Index) {
450e5dd7070Spatrick   if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
451e5dd7070Spatrick     if (Index < D->getNumDiagnostics())
452e5dd7070Spatrick       return D->getDiagnostic(Index);
453e5dd7070Spatrick   return nullptr;
454e5dd7070Spatrick }
455e5dd7070Spatrick 
clang_getChildDiagnostics(CXDiagnostic Diag)456e5dd7070Spatrick CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
457e5dd7070Spatrick   if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
458e5dd7070Spatrick     CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
459e5dd7070Spatrick     return ChildDiags.empty() ? nullptr : (CXDiagnosticSet) &ChildDiags;
460e5dd7070Spatrick   }
461e5dd7070Spatrick   return nullptr;
462e5dd7070Spatrick }
463e5dd7070Spatrick 
clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags)464e5dd7070Spatrick unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
465e5dd7070Spatrick   if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
466e5dd7070Spatrick     return D->getNumDiagnostics();
467e5dd7070Spatrick   return 0;
468e5dd7070Spatrick }
469