Coverage Report

Created: 2020-02-25 14:32

/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
1.97k
CXDiagnosticSetImpl::~CXDiagnosticSetImpl() {}
31
32
void
33
908
CXDiagnosticSetImpl::appendDiagnostic(std::unique_ptr<CXDiagnosticImpl> D) {
34
908
  Diagnostics.push_back(std::move(D));
35
908
}
36
37
1.48k
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
477
    CurrentSet(mainSet), MainSet(mainSet) {}
89
90
477
  ~CXDiagnosticRenderer() override {}
91
92
  void beginDiagnostic(DiagOrStoredDiag D,
93
611
                       DiagnosticsEngine::Level Level) override {
94
611
95
611
    const StoredDiagnostic *SD = D.dyn_cast<const StoredDiagnostic*>();
96
611
    if (!SD)
97
16
      return;
98
595
    
99
595
    if (Level != DiagnosticsEngine::Note)
100
385
      CurrentSet = MainSet;
101
595
102
595
    auto Owner = std::make_unique<CXStoredDiagnostic>(*SD, LangOpts);
103
595
    CXStoredDiagnostic &CD = *Owner;
104
595
    CurrentSet->appendDiagnostic(std::move(Owner));
105
595
106
595
    if (Level != DiagnosticsEngine::Note)
107
385
      CurrentSet = &CD.getChildDiagnostics();
108
595
  }
109
110
  void emitDiagnosticMessage(FullSourceLoc Loc, PresumedLoc PLoc,
111
                             DiagnosticsEngine::Level Level, StringRef Message,
112
                             ArrayRef<CharSourceRange> Ranges,
113
611
                             DiagOrStoredDiag D) override {
114
611
    if (!D.isNull())
115
595
      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
595
                       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
616
                                             bool checkIfChanged) {
151
616
  ASTUnit *AU = cxtu::getASTUnit(TU);
152
616
153
616
  if (TU->Diagnostics && 
checkIfChanged141
) {
154
99
    // In normal use, ASTUnit's diagnostics should not change unless we reparse.
155
99
    // Currently they can only change by using the internal testing flag
156
99
    // '-error-on-deserialized-decl' which will error during deserialization of
157
99
    // a declaration. What will happen is:
158
99
    //
159
99
    //  -c-index-test gets a CXTranslationUnit
160
99
    //  -checks the diagnostics, the diagnostics set is lazily created,
161
99
    //     no errors are reported
162
99
    //  -later does an operation, like annotation of tokens, that triggers
163
99
    //     -error-on-deserialized-decl, that will emit a diagnostic error,
164
99
    //     that ASTUnit will catch and add to its stored diagnostics vector.
165
99
    //  -c-index-test wants to check whether an error occurred after performing
166
99
    //     the operation but can only query the lazily created set.
167
99
    //
168
99
    // We check here if a new diagnostic was appended since the last time the
169
99
    // 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
2
      // Diagnostics in the ASTUnit were updated, reset the associated
175
2
      // diagnostics.
176
2
      delete Set;
177
2
      TU->Diagnostics = nullptr;
178
2
    }
179
99
  }
180
616
181
616
  if (!TU->Diagnostics) {
182
477
    CXDiagnosticSetImpl *Set = new CXDiagnosticSetImpl();
183
477
    TU->Diagnostics = Set;
184
477
    IntrusiveRefCntPtr<DiagnosticOptions> DOpts = new DiagnosticOptions;
185
477
    CXDiagnosticRenderer Renderer(AU->getASTContext().getLangOpts(),
186
477
                                  &*DOpts, Set);
187
477
    
188
477
    for (ASTUnit::stored_diag_iterator it = AU->stored_diag_begin(),
189
1.07k
         ei = AU->stored_diag_end(); it != ei; 
++it595
) {
190
595
      Renderer.emitStoredDiagnostic(*it);
191
595
    }
192
477
  }
193
616
  return static_cast<CXDiagnosticSetImpl*>(TU->Diagnostics);
194
616
}
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
372
CXDiagnosticSet clang_getDiagnosticSetFromTU(CXTranslationUnit Unit) {
227
372
  if (cxtu::isNotUsableTU(Unit)) {
228
0
    LOG_BAD_TU(Unit);
229
0
    return nullptr;
230
0
  }
231
372
  if (!cxtu::getASTUnit(Unit))
232
0
    return nullptr;
233
372
  return static_cast<CXDiagnostic>(lazyCreateDiags(Unit));
234
372
}
235
236
195
void clang_disposeDiagnostic(CXDiagnostic Diagnostic) {
237
195
  // No-op.  Kept as a legacy API.  CXDiagnostics are now managed
238
195
  // by the enclosing CXDiagnosticSet.
239
195
}
240
241
1.40k
CXString clang_formatDiagnostic(CXDiagnostic Diagnostic, unsigned Options) {
242
1.40k
  if (!Diagnostic)
243
0
    return cxstring::createEmpty();
244
1.40k
245
1.40k
  CXDiagnosticSeverity Severity = clang_getDiagnosticSeverity(Diagnostic);
246
1.40k
247
1.40k
  SmallString<256> Str;
248
1.40k
  llvm::raw_svector_ostream Out(Str);
249
1.40k
  
250
1.40k
  if (Options & CXDiagnostic_DisplaySourceLocation) {
251
1.40k
    // Print source location (file:line), along with optional column
252
1.40k
    // and source ranges.
253
1.40k
    CXFile File;
254
1.40k
    unsigned Line, Column;
255
1.40k
    clang_getSpellingLocation(clang_getDiagnosticLocation(Diagnostic),
256
1.40k
                              &File, &Line, &Column, nullptr);
257
1.40k
    if (File) {
258
1.36k
      CXString FName = clang_getFileName(File);
259
1.36k
      Out << clang_getCString(FName) << ":" << Line << ":";
260
1.36k
      clang_disposeString(FName);
261
1.36k
      if (Options & CXDiagnostic_DisplayColumn)
262
1.36k
        Out << Column << ":";
263
1.36k
264
1.36k
      if (Options & CXDiagnostic_DisplaySourceRanges) {
265
941
        unsigned N = clang_getDiagnosticNumRanges(Diagnostic);
266
941
        bool PrintedRange = false;
267
1.01k
        for (unsigned I = 0; I != N; 
++I74
) {
268
74
          CXFile StartFile, EndFile;
269
74
          CXSourceRange Range = clang_getDiagnosticRange(Diagnostic, I);
270
74
          
271
74
          unsigned StartLine, StartColumn, EndLine, EndColumn;
272
74
          clang_getSpellingLocation(clang_getRangeStart(Range),
273
74
                                    &StartFile, &StartLine, &StartColumn,
274
74
                                    nullptr);
275
74
          clang_getSpellingLocation(clang_getRangeEnd(Range),
276
74
                                    &EndFile, &EndLine, &EndColumn, nullptr);
277
74
278
74
          if (StartFile != EndFile || 
StartFile != File65
)
279
19
            continue;
280
55
          
281
55
          Out << "{" << StartLine << ":" << StartColumn << "-"
282
55
              << EndLine << ":" << EndColumn << "}";
283
55
          PrintedRange = true;
284
55
        }
285
941
        if (PrintedRange)
286
54
          Out << ":";
287
941
      }
288
1.36k
      
289
1.36k
      Out << " ";
290
1.36k
    }
291
1.40k
  }
292
1.40k
293
1.40k
  /* Print warning/error/etc. */
294
1.40k
  switch (Severity) {
295
0
  case CXDiagnostic_Ignored: llvm_unreachable("impossible");
296
605
  case CXDiagnostic_Note: Out << "note: "; break;
297
327
  case CXDiagnostic_Warning: Out << "warning: "; break;
298
457
  case CXDiagnostic_Error: Out << "error: "; break;
299
12
  case CXDiagnostic_Fatal: Out << "fatal error: "; break;
300
1.40k
  }
301
1.40k
302
1.40k
  CXString Text = clang_getDiagnosticSpelling(Diagnostic);
303
1.40k
  if (clang_getCString(Text))
304
1.40k
    Out << clang_getCString(Text);
305
0
  else
306
0
    Out << "<no diagnostic text>";
307
1.40k
  clang_disposeString(Text);
308
1.40k
  
309
1.40k
  if (Options & (CXDiagnostic_DisplayOption | CXDiagnostic_DisplayCategoryId |
310
1.40k
                 CXDiagnostic_DisplayCategoryName)) {
311
1.40k
    bool NeedBracket = true;
312
1.40k
    bool NeedComma = false;
313
1.40k
314
1.40k
    if (Options & CXDiagnostic_DisplayOption) {
315
1.40k
      CXString OptionName = clang_getDiagnosticOption(Diagnostic, nullptr);
316
1.40k
      if (const char *OptionText = clang_getCString(OptionName)) {
317
1.40k
        if (OptionText[0]) {
318
324
          Out << " [" << OptionText;
319
324
          NeedBracket = false;
320
324
          NeedComma = true;
321
324
        }
322
1.40k
      }
323
1.40k
      clang_disposeString(OptionName);
324
1.40k
    }
325
1.40k
    
326
1.40k
    if (Options & (CXDiagnostic_DisplayCategoryId | 
327
1.40k
                   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.40k
353
1.40k
    (void) NeedComma; // Silence dead store warning.
354
1.40k
    if (!NeedBracket)
355
324
      Out << "]";
356
1.40k
  }
357
1.40k
  
358
1.40k
  return cxstring::createDup(Out.str());
359
1.40k
}
360
361
432
unsigned clang_defaultDiagnosticDisplayOptions() {
362
432
  return CXDiagnostic_DisplaySourceLocation | CXDiagnostic_DisplayColumn |
363
432
         CXDiagnostic_DisplayOption;
364
432
}
365
366
2.44k
enum CXDiagnosticSeverity clang_getDiagnosticSeverity(CXDiagnostic Diag) {
367
2.44k
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
368
2.44k
    return D->getSeverity();
369
0
  return CXDiagnostic_Ignored;
370
0
}
371
372
2.44k
CXSourceLocation clang_getDiagnosticLocation(CXDiagnostic Diag) {
373
2.44k
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl*>(Diag))
374
2.44k
    return D->getLocation();
375
0
  return clang_getNullLocation();
376
0
}
377
378
1.47k
CXString clang_getDiagnosticSpelling(CXDiagnostic Diag) {
379
1.47k
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
380
1.47k
    return D->getSpelling();
381
0
  return cxstring::createEmpty();
382
0
}
383
384
1.47k
CXString clang_getDiagnosticOption(CXDiagnostic Diag, CXString *Disable) {
385
1.47k
  if (Disable)
386
0
    *Disable = cxstring::createEmpty();
387
1.47k
388
1.47k
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
389
1.47k
    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
0
  // Kept for backward compatibility.
402
0
  return cxstring::createRef(DiagnosticIDs::getCategoryNameFromID(Category));
403
0
}
404
  
405
73
CXString clang_getDiagnosticCategoryText(CXDiagnostic Diag) {
406
73
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
407
73
    return D->getCategoryText();
408
0
  return cxstring::createEmpty();
409
0
}
410
  
411
1.01k
unsigned clang_getDiagnosticNumRanges(CXDiagnostic Diag) {
412
1.01k
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
413
1.01k
    return D->getNumRanges();
414
0
  return 0;
415
0
}
416
417
110
CXSourceRange clang_getDiagnosticRange(CXDiagnostic Diag, unsigned Range) {
418
110
  CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag);  
419
110
  if (!D || Range >= D->getNumRanges())
420
0
    return clang_getNullRange();
421
110
  return D->getRange(Range);
422
110
}
423
424
1.01k
unsigned clang_getDiagnosticNumFixIts(CXDiagnostic Diag) {
425
1.01k
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag))
426
1.01k
    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
380
void clang_disposeDiagnosticSet(CXDiagnosticSet Diags) {
442
380
  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl *>(Diags)) {
443
380
    if (D->isExternallyManaged())
444
15
      delete D;
445
380
  }
446
380
}
447
  
448
CXDiagnostic clang_getDiagnosticInSet(CXDiagnosticSet Diags,
449
885
                                      unsigned Index) {
450
885
  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
451
885
    if (Index < D->getNumDiagnostics())
452
885
      return D->getDiagnostic(Index);
453
0
  return nullptr;
454
0
}
455
  
456
854
CXDiagnosticSet clang_getChildDiagnostics(CXDiagnostic Diag) {
457
854
  if (CXDiagnosticImpl *D = static_cast<CXDiagnosticImpl *>(Diag)) {
458
854
    CXDiagnosticSetImpl &ChildDiags = D->getChildDiagnostics();
459
854
    return ChildDiags.empty() ? 
nullptr612
:
(CXDiagnosticSet) &ChildDiags242
;
460
854
  }
461
0
  return nullptr;
462
0
}
463
464
689
unsigned clang_getNumDiagnosticsInSet(CXDiagnosticSet Diags) {
465
689
  if (CXDiagnosticSetImpl *D = static_cast<CXDiagnosticSetImpl*>(Diags))
466
689
    return D->getNumDiagnostics();
467
0
  return 0;
468
0
}