Coverage Report

Created: 2020-09-19 12:23

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