Coverage Report

Created: 2022-01-22 13:19

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/AST/CommentSema.cpp
Line
Count
Source (jump to first uncovered line)
1
//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
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
#include "clang/AST/CommentSema.h"
10
#include "clang/AST/Attr.h"
11
#include "clang/AST/CommentCommandTraits.h"
12
#include "clang/AST/CommentDiagnostic.h"
13
#include "clang/AST/Decl.h"
14
#include "clang/AST/DeclTemplate.h"
15
#include "clang/Basic/LLVM.h"
16
#include "clang/Basic/SourceManager.h"
17
#include "clang/Lex/Preprocessor.h"
18
#include "llvm/ADT/SmallString.h"
19
#include "llvm/ADT/StringSwitch.h"
20
21
namespace clang {
22
namespace comments {
23
24
namespace {
25
#include "clang/AST/CommentHTMLTagsProperties.inc"
26
} // end anonymous namespace
27
28
Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
29
           DiagnosticsEngine &Diags, CommandTraits &Traits,
30
           const Preprocessor *PP) :
31
    Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
32
    PP(PP), ThisDeclInfo(nullptr), BriefCommand(nullptr),
33
1.70k
    HeaderfileCommand(nullptr) {
34
1.70k
}
35
36
1.62k
void Sema::setDecl(const Decl *D) {
37
1.62k
  if (!D)
38
0
    return;
39
40
1.62k
  ThisDeclInfo = new (Allocator) DeclInfo;
41
1.62k
  ThisDeclInfo->CommentDecl = D;
42
1.62k
  ThisDeclInfo->IsFilled = false;
43
1.62k
}
44
45
ParagraphComment *Sema::actOnParagraphComment(
46
3.66k
                              ArrayRef<InlineContentComment *> Content) {
47
3.66k
  return new (Allocator) ParagraphComment(Content);
48
3.66k
}
49
50
BlockCommandComment *Sema::actOnBlockCommandStart(
51
                                      SourceLocation LocBegin,
52
                                      SourceLocation LocEnd,
53
                                      unsigned CommandID,
54
1.01k
                                      CommandMarkerKind CommandMarker) {
55
1.01k
  BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd,
56
1.01k
                                                                CommandID,
57
1.01k
                                                                CommandMarker);
58
1.01k
  checkContainerDecl(BC);
59
1.01k
  return BC;
60
1.01k
}
61
62
void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
63
0
                                 ArrayRef<BlockCommandComment::Argument> Args) {
64
0
  Command->setArgs(Args);
65
0
}
66
67
void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
68
1.01k
                                   ParagraphComment *Paragraph) {
69
1.01k
  Command->setParagraph(Paragraph);
70
1.01k
  checkBlockCommandEmptyParagraph(Command);
71
1.01k
  checkBlockCommandDuplicate(Command);
72
1.01k
  if (ThisDeclInfo) {
73
    // These checks only make sense if the comment is attached to a
74
    // declaration.
75
1.00k
    checkReturnsCommand(Command);
76
1.00k
    checkDeprecatedCommand(Command);
77
1.00k
  }
78
1.01k
}
79
80
ParamCommandComment *Sema::actOnParamCommandStart(
81
                                      SourceLocation LocBegin,
82
                                      SourceLocation LocEnd,
83
                                      unsigned CommandID,
84
514
                                      CommandMarkerKind CommandMarker) {
85
514
  ParamCommandComment *Command =
86
514
      new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID,
87
514
                                          CommandMarker);
88
89
514
  if (!involvesFunctionType())
90
53
    Diag(Command->getLocation(),
91
53
         diag::warn_doc_param_not_attached_to_a_function_decl)
92
53
      << CommandMarker
93
53
      << Command->getCommandNameRange(Traits);
94
95
514
  return Command;
96
514
}
97
98
107
void Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) {
99
107
  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
100
107
  if (!Info->IsFunctionDeclarationCommand)
101
85
    return;
102
103
22
  unsigned DiagSelect;
104
22
  switch (Comment->getCommandID()) {
105
11
    case CommandTraits::KCI_function:
106
11
      DiagSelect = (!isAnyFunctionDecl() && 
!isFunctionTemplateDecl()6
)?
13
:
08
;
107
11
      break;
108
0
    case CommandTraits::KCI_functiongroup:
109
0
      DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0;
110
0
      break;
111
6
    case CommandTraits::KCI_method:
112
6
      DiagSelect = !isObjCMethodDecl() ? 3 : 
00
;
113
6
      break;
114
2
    case CommandTraits::KCI_methodgroup:
115
2
      DiagSelect = !isObjCMethodDecl() ? 4 : 
00
;
116
2
      break;
117
3
    case CommandTraits::KCI_callback:
118
3
      DiagSelect = !isFunctionPointerVarDecl() ? 5 : 
00
;
119
3
      break;
120
0
    default:
121
0
      DiagSelect = 0;
122
0
      break;
123
22
  }
124
22
  if (DiagSelect)
125
14
    Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch)
126
14
    << Comment->getCommandMarker()
127
14
    << (DiagSelect-1) << (DiagSelect-1)
128
14
    << Comment->getSourceRange();
129
22
}
130
131
107
void Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) {
132
107
  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
133
107
  if (!Info->IsRecordLikeDeclarationCommand)
134
57
    return;
135
50
  unsigned DiagSelect;
136
50
  switch (Comment->getCommandID()) {
137
18
    case CommandTraits::KCI_class:
138
18
      DiagSelect =
139
18
          (!isClassOrStructOrTagTypedefDecl() && 
!isClassTemplateDecl()7
) ?
14
140
18
                                                                         : 
014
;
141
      // Allow @class command on @interface declarations.
142
      // FIXME. Currently, \class and @class are indistinguishable. So,
143
      // \class is also allowed on an @interface declaration
144
18
      if (DiagSelect && 
Comment->getCommandMarker()4
&&
isObjCInterfaceDecl()4
)
145
2
        DiagSelect = 0;
146
18
      break;
147
9
    case CommandTraits::KCI_interface:
148
9
      DiagSelect = !isObjCInterfaceDecl() ? 
24
:
05
;
149
9
      break;
150
6
    case CommandTraits::KCI_protocol:
151
6
      DiagSelect = !isObjCProtocolDecl() ? 
34
:
02
;
152
6
      break;
153
11
    case CommandTraits::KCI_struct:
154
11
      DiagSelect = !isClassOrStructOrTagTypedefDecl() ? 
45
:
06
;
155
11
      break;
156
6
    case CommandTraits::KCI_union:
157
6
      DiagSelect = !isUnionDecl() ? 
53
:
03
;
158
6
      break;
159
0
    default:
160
0
      DiagSelect = 0;
161
0
      break;
162
50
  }
163
50
  if (DiagSelect)
164
18
    Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch)
165
18
    << Comment->getCommandMarker()
166
18
    << (DiagSelect-1) << (DiagSelect-1)
167
18
    << Comment->getSourceRange();
168
50
}
169
170
1.01k
void Sema::checkContainerDecl(const BlockCommandComment *Comment) {
171
1.01k
  const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID());
172
1.01k
  if (!Info->IsRecordLikeDetailCommand || 
isRecordLikeDecl()4
)
173
1.01k
    return;
174
4
  unsigned DiagSelect;
175
4
  switch (Comment->getCommandID()) {
176
2
    case CommandTraits::KCI_classdesign:
177
2
      DiagSelect = 1;
178
2
      break;
179
2
    case CommandTraits::KCI_coclass:
180
2
      DiagSelect = 2;
181
2
      break;
182
0
    case CommandTraits::KCI_dependency:
183
0
      DiagSelect = 3;
184
0
      break;
185
0
    case CommandTraits::KCI_helper:
186
0
      DiagSelect = 4;
187
0
      break;
188
0
    case CommandTraits::KCI_helperclass:
189
0
      DiagSelect = 5;
190
0
      break;
191
0
    case CommandTraits::KCI_helps:
192
0
      DiagSelect = 6;
193
0
      break;
194
0
    case CommandTraits::KCI_instancesize:
195
0
      DiagSelect = 7;
196
0
      break;
197
0
    case CommandTraits::KCI_ownership:
198
0
      DiagSelect = 8;
199
0
      break;
200
0
    case CommandTraits::KCI_performance:
201
0
      DiagSelect = 9;
202
0
      break;
203
0
    case CommandTraits::KCI_security:
204
0
      DiagSelect = 10;
205
0
      break;
206
0
    case CommandTraits::KCI_superclass:
207
0
      DiagSelect = 11;
208
0
      break;
209
0
    default:
210
0
      DiagSelect = 0;
211
0
      break;
212
4
  }
213
4
  if (DiagSelect)
214
4
    Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch)
215
4
    << Comment->getCommandMarker()
216
4
    << (DiagSelect-1)
217
4
    << Comment->getSourceRange();
218
4
}
219
220
/// Turn a string into the corresponding PassDirection or -1 if it's not
221
/// valid.
222
65
static int getParamPassDirection(StringRef Arg) {
223
65
  return llvm::StringSwitch<int>(Arg)
224
65
      .Case("[in]", ParamCommandComment::In)
225
65
      .Case("[out]", ParamCommandComment::Out)
226
65
      .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut)
227
65
      .Default(-1);
228
65
}
229
230
void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
231
                                         SourceLocation ArgLocBegin,
232
                                         SourceLocation ArgLocEnd,
233
54
                                         StringRef Arg) {
234
54
  std::string ArgLower = Arg.lower();
235
54
  int Direction = getParamPassDirection(ArgLower);
236
237
54
  if (Direction == -1) {
238
    // Try again with whitespace removed.
239
11
    llvm::erase_if(ArgLower, clang::isWhitespace);
240
11
    Direction = getParamPassDirection(ArgLower);
241
242
11
    SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
243
11
    if (Direction != -1) {
244
8
      const char *FixedName = ParamCommandComment::getDirectionAsString(
245
8
          (ParamCommandComment::PassDirection)Direction);
246
8
      Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
247
8
          << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName);
248
8
    } else {
249
3
      Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange;
250
3
      Direction = ParamCommandComment::In; // Sane fall back.
251
3
    }
252
11
  }
253
54
  Command->setDirection((ParamCommandComment::PassDirection)Direction,
254
54
                        /*Explicit=*/true);
255
54
}
256
257
void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
258
                                         SourceLocation ArgLocBegin,
259
                                         SourceLocation ArgLocEnd,
260
505
                                         StringRef Arg) {
261
  // Parser will not feed us more arguments than needed.
262
505
  assert(Command->getNumArgs() == 0);
263
264
505
  if (!Command->isDirectionExplicit()) {
265
    // User didn't provide a direction argument.
266
451
    Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
267
451
  }
268
505
  typedef BlockCommandComment::Argument Argument;
269
505
  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
270
505
                                                     ArgLocEnd),
271
505
                                         Arg);
272
505
  Command->setArgs(llvm::makeArrayRef(A, 1));
273
505
}
274
275
void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
276
514
                                   ParagraphComment *Paragraph) {
277
514
  Command->setParagraph(Paragraph);
278
514
  checkBlockCommandEmptyParagraph(Command);
279
514
}
280
281
TParamCommandComment *Sema::actOnTParamCommandStart(
282
                                      SourceLocation LocBegin,
283
                                      SourceLocation LocEnd,
284
                                      unsigned CommandID,
285
207
                                      CommandMarkerKind CommandMarker) {
286
207
  TParamCommandComment *Command =
287
207
      new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID,
288
207
                                           CommandMarker);
289
290
207
  if (!isTemplateOrSpecialization())
291
28
    Diag(Command->getLocation(),
292
28
         diag::warn_doc_tparam_not_attached_to_a_template_decl)
293
28
      << CommandMarker
294
28
      << Command->getCommandNameRange(Traits);
295
296
207
  return Command;
297
207
}
298
299
void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
300
                                          SourceLocation ArgLocBegin,
301
                                          SourceLocation ArgLocEnd,
302
199
                                          StringRef Arg) {
303
  // Parser will not feed us more arguments than needed.
304
199
  assert(Command->getNumArgs() == 0);
305
306
0
  typedef BlockCommandComment::Argument Argument;
307
199
  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
308
199
                                                     ArgLocEnd),
309
199
                                         Arg);
310
199
  Command->setArgs(llvm::makeArrayRef(A, 1));
311
312
199
  if (!isTemplateOrSpecialization()) {
313
    // We already warned that this \\tparam is not attached to a template decl.
314
27
    return;
315
27
  }
316
317
172
  const TemplateParameterList *TemplateParameters =
318
172
      ThisDeclInfo->TemplateParameters;
319
172
  SmallVector<unsigned, 2> Position;
320
172
  if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
321
121
    Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
322
121
    TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg];
323
121
    if (PrevCommand) {
324
3
      SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
325
3
      Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
326
3
        << Arg << ArgRange;
327
3
      Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
328
3
        << PrevCommand->getParamNameRange();
329
3
    }
330
121
    PrevCommand = Command;
331
121
    return;
332
121
  }
333
334
51
  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
335
51
  Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
336
51
    << Arg << ArgRange;
337
338
51
  if (!TemplateParameters || 
TemplateParameters->size() == 048
)
339
12
    return;
340
341
39
  StringRef CorrectedName;
342
39
  if (TemplateParameters->size() == 1) {
343
28
    const NamedDecl *Param = TemplateParameters->getParam(0);
344
28
    const IdentifierInfo *II = Param->getIdentifier();
345
28
    if (II)
346
28
      CorrectedName = II->getName();
347
28
  } else {
348
11
    CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
349
11
  }
350
351
39
  if (!CorrectedName.empty()) {
352
35
    Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
353
35
      << CorrectedName
354
35
      << FixItHint::CreateReplacement(ArgRange, CorrectedName);
355
35
  }
356
39
}
357
358
void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
359
207
                                    ParagraphComment *Paragraph) {
360
207
  Command->setParagraph(Paragraph);
361
207
  checkBlockCommandEmptyParagraph(Command);
362
207
}
363
364
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
365
                                               SourceLocation CommandLocEnd,
366
23
                                               unsigned CommandID) {
367
23
  ArrayRef<InlineCommandComment::Argument> Args;
368
23
  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
369
23
  return new (Allocator) InlineCommandComment(
370
23
                                  CommandLocBegin,
371
23
                                  CommandLocEnd,
372
23
                                  CommandID,
373
23
                                  getInlineCommandRenderKind(CommandName),
374
23
                                  Args);
375
23
}
376
377
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
378
                                               SourceLocation CommandLocEnd,
379
                                               unsigned CommandID,
380
                                               SourceLocation ArgLocBegin,
381
                                               SourceLocation ArgLocEnd,
382
61
                                               StringRef Arg) {
383
61
  typedef InlineCommandComment::Argument Argument;
384
61
  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
385
61
                                                     ArgLocEnd),
386
61
                                         Arg);
387
61
  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
388
389
61
  return new (Allocator) InlineCommandComment(
390
61
                                  CommandLocBegin,
391
61
                                  CommandLocEnd,
392
61
                                  CommandID,
393
61
                                  getInlineCommandRenderKind(CommandName),
394
61
                                  llvm::makeArrayRef(A, 1));
395
61
}
396
397
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
398
                                                SourceLocation LocEnd,
399
154
                                                StringRef CommandName) {
400
154
  unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
401
154
  return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
402
154
}
403
404
InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
405
                                                SourceLocation LocEnd,
406
158
                                                unsigned CommandID) {
407
158
  ArrayRef<InlineCommandComment::Argument> Args;
408
158
  return new (Allocator) InlineCommandComment(
409
158
                                  LocBegin, LocEnd, CommandID,
410
158
                                  InlineCommandComment::RenderNormal,
411
158
                                  Args);
412
158
}
413
414
TextComment *Sema::actOnText(SourceLocation LocBegin,
415
                             SourceLocation LocEnd,
416
4.12k
                             StringRef Text) {
417
4.12k
  return new (Allocator) TextComment(LocBegin, LocEnd, Text);
418
4.12k
}
419
420
VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
421
53
                                                    unsigned CommandID) {
422
53
  StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
423
53
  return new (Allocator) VerbatimBlockComment(
424
53
                                  Loc,
425
53
                                  Loc.getLocWithOffset(1 + CommandName.size()),
426
53
                                  CommandID);
427
53
}
428
429
VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
430
73
                                                       StringRef Text) {
431
73
  return new (Allocator) VerbatimBlockLineComment(Loc, Text);
432
73
}
433
434
void Sema::actOnVerbatimBlockFinish(
435
                            VerbatimBlockComment *Block,
436
                            SourceLocation CloseNameLocBegin,
437
                            StringRef CloseName,
438
53
                            ArrayRef<VerbatimBlockLineComment *> Lines) {
439
53
  Block->setCloseName(CloseName, CloseNameLocBegin);
440
53
  Block->setLines(Lines);
441
53
}
442
443
VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
444
                                             unsigned CommandID,
445
                                             SourceLocation TextBegin,
446
107
                                             StringRef Text) {
447
107
  VerbatimLineComment *VL = new (Allocator) VerbatimLineComment(
448
107
                              LocBegin,
449
107
                              TextBegin.getLocWithOffset(Text.size()),
450
107
                              CommandID,
451
107
                              TextBegin,
452
107
                              Text);
453
107
  checkFunctionDeclVerbatimLine(VL);
454
107
  checkContainerDeclVerbatimLine(VL);
455
107
  return VL;
456
107
}
457
458
HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
459
123
                                                  StringRef TagName) {
460
123
  return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
461
123
}
462
463
void Sema::actOnHTMLStartTagFinish(
464
                              HTMLStartTagComment *Tag,
465
                              ArrayRef<HTMLStartTagComment::Attribute> Attrs,
466
                              SourceLocation GreaterLoc,
467
123
                              bool IsSelfClosing) {
468
123
  Tag->setAttrs(Attrs);
469
123
  Tag->setGreaterLoc(GreaterLoc);
470
123
  if (IsSelfClosing)
471
12
    Tag->setSelfClosing();
472
111
  else if (!isHTMLEndTagForbidden(Tag->getTagName()))
473
97
    HTMLOpenTags.push_back(Tag);
474
123
}
475
476
HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
477
                                         SourceLocation LocEnd,
478
64
                                         StringRef TagName) {
479
64
  HTMLEndTagComment *HET =
480
64
      new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
481
64
  if (isHTMLEndTagForbidden(TagName)) {
482
3
    Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
483
3
      << TagName << HET->getSourceRange();
484
3
    HET->setIsMalformed();
485
3
    return HET;
486
3
  }
487
488
61
  bool FoundOpen = false;
489
61
  for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
490
61
       I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
491
75
       I != E; 
++I14
) {
492
57
    if ((*I)->getTagName() == TagName) {
493
43
      FoundOpen = true;
494
43
      break;
495
43
    }
496
57
  }
497
61
  if (!FoundOpen) {
498
18
    Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
499
18
      << HET->getSourceRange();
500
18
    HET->setIsMalformed();
501
18
    return HET;
502
18
  }
503
504
49
  
while (43
!HTMLOpenTags.empty()) {
505
49
    HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
506
49
    StringRef LastNotClosedTagName = HST->getTagName();
507
49
    if (LastNotClosedTagName == TagName) {
508
      // If the start tag is malformed, end tag is malformed as well.
509
43
      if (HST->isMalformed())
510
0
        HET->setIsMalformed();
511
43
      break;
512
43
    }
513
514
6
    if (isHTMLEndTagOptional(LastNotClosedTagName))
515
0
      continue;
516
517
6
    bool OpenLineInvalid;
518
6
    const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
519
6
                                                HST->getLocation(),
520
6
                                                &OpenLineInvalid);
521
6
    bool CloseLineInvalid;
522
6
    const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
523
6
                                                HET->getLocation(),
524
6
                                                &CloseLineInvalid);
525
526
6
    if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) {
527
6
      Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
528
6
        << HST->getTagName() << HET->getTagName()
529
6
        << HST->getSourceRange() << HET->getSourceRange();
530
6
      HST->setIsMalformed();
531
6
    } else {
532
0
      Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
533
0
        << HST->getTagName() << HET->getTagName()
534
0
        << HST->getSourceRange();
535
0
      Diag(HET->getLocation(), diag::note_doc_html_end_tag)
536
0
        << HET->getSourceRange();
537
0
      HST->setIsMalformed();
538
0
    }
539
6
  }
540
541
43
  return HET;
542
61
}
543
544
FullComment *Sema::actOnFullComment(
545
1.70k
                              ArrayRef<BlockContentComment *> Blocks) {
546
1.70k
  FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
547
1.70k
  resolveParamCommandIndexes(FC);
548
549
  // Complain about HTML tags that are not closed.
550
1.75k
  while (!HTMLOpenTags.empty()) {
551
48
    HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val();
552
48
    if (isHTMLEndTagOptional(HST->getTagName()))
553
0
      continue;
554
555
48
    Diag(HST->getLocation(), diag::warn_doc_html_missing_end_tag)
556
48
      << HST->getTagName() << HST->getSourceRange();
557
48
    HST->setIsMalformed();
558
48
  }
559
560
1.70k
  return FC;
561
1.70k
}
562
563
1.73k
void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
564
1.73k
  if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
565
76
    return;
566
567
1.66k
  ParagraphComment *Paragraph = Command->getParagraph();
568
1.66k
  if (Paragraph->isWhitespace()) {
569
261
    SourceLocation DiagLoc;
570
261
    if (Command->getNumArgs() > 0)
571
36
      DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
572
261
    if (!DiagLoc.isValid())
573
225
      DiagLoc = Command->getCommandNameRange(Traits).getEnd();
574
261
    Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
575
261
      << Command->getCommandMarker()
576
261
      << Command->getCommandName(Traits)
577
261
      << Command->getSourceRange();
578
261
  }
579
1.66k
}
580
581
1.00k
void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
582
1.00k
  if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
583
749
    return;
584
585
259
  assert(ThisDeclInfo && "should not call this check on a bare comment");
586
587
  // We allow the return command for all @properties because it can be used
588
  // to document the value that the property getter returns.
589
259
  if (isObjCPropertyDecl())
590
8
    return;
591
251
  if (involvesFunctionType()) {
592
188
    assert(!ThisDeclInfo->ReturnType.isNull() &&
593
188
           "should have a valid return type");
594
188
    if (ThisDeclInfo->ReturnType->isVoidType()) {
595
44
      unsigned DiagKind;
596
44
      switch (ThisDeclInfo->CommentDecl->getKind()) {
597
38
      default:
598
38
        if (ThisDeclInfo->IsObjCMethod)
599
2
          DiagKind = 3;
600
36
        else
601
36
          DiagKind = 0;
602
38
        break;
603
3
      case Decl::CXXConstructor:
604
3
        DiagKind = 1;
605
3
        break;
606
3
      case Decl::CXXDestructor:
607
3
        DiagKind = 2;
608
3
        break;
609
44
      }
610
44
      Diag(Command->getLocation(),
611
44
           diag::warn_doc_returns_attached_to_a_void_function)
612
44
        << Command->getCommandMarker()
613
44
        << Command->getCommandName(Traits)
614
44
        << DiagKind
615
44
        << Command->getSourceRange();
616
44
    }
617
188
    return;
618
188
  }
619
620
63
  Diag(Command->getLocation(),
621
63
       diag::warn_doc_returns_not_attached_to_a_function_decl)
622
63
    << Command->getCommandMarker()
623
63
    << Command->getCommandName(Traits)
624
63
    << Command->getSourceRange();
625
63
}
626
627
1.01k
void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
628
1.01k
  const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
629
1.01k
  const BlockCommandComment *PrevCommand = nullptr;
630
1.01k
  if (Info->IsBriefCommand) {
631
440
    if (!BriefCommand) {
632
426
      BriefCommand = Command;
633
426
      return;
634
426
    }
635
14
    PrevCommand = BriefCommand;
636
577
  } else if (Info->IsHeaderfileCommand) {
637
11
    if (!HeaderfileCommand) {
638
8
      HeaderfileCommand = Command;
639
8
      return;
640
8
    }
641
3
    PrevCommand = HeaderfileCommand;
642
566
  } else {
643
    // We don't want to check this command for duplicates.
644
566
    return;
645
566
  }
646
17
  StringRef CommandName = Command->getCommandName(Traits);
647
17
  StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
648
17
  Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
649
17
      << Command->getCommandMarker()
650
17
      << CommandName
651
17
      << Command->getSourceRange();
652
17
  if (CommandName == PrevCommandName)
653
13
    Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
654
13
        << PrevCommand->getCommandMarker()
655
13
        << PrevCommandName
656
13
        << PrevCommand->getSourceRange();
657
4
  else
658
4
    Diag(PrevCommand->getLocation(),
659
4
         diag::note_doc_block_command_previous_alias)
660
4
        << PrevCommand->getCommandMarker()
661
4
        << PrevCommandName
662
4
        << CommandName;
663
17
}
664
665
1.00k
void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
666
1.00k
  if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
667
934
    return;
668
669
74
  assert(ThisDeclInfo && "should not call this check on a bare comment");
670
671
0
  const Decl *D = ThisDeclInfo->CommentDecl;
672
74
  if (!D)
673
0
    return;
674
675
74
  if (D->hasAttr<DeprecatedAttr>() ||
676
74
      
D->hasAttr<AvailabilityAttr>()66
||
677
74
      
D->hasAttr<UnavailableAttr>()63
)
678
14
    return;
679
680
60
  Diag(Command->getLocation(), diag::warn_doc_deprecated_not_sync)
681
60
      << Command->getSourceRange() << Command->getCommandMarker();
682
683
  // Try to emit a fixit with a deprecation attribute.
684
60
  if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
685
    // Don't emit a Fix-It for non-member function definitions.  GCC does not
686
    // accept attributes on them.
687
57
    const DeclContext *Ctx = FD->getDeclContext();
688
57
    if ((!Ctx || !Ctx->isRecord()) &&
689
57
        
FD->doesThisDeclarationHaveABody()21
)
690
1
      return;
691
692
56
    const LangOptions &LO = FD->getLangOpts();
693
56
    const bool DoubleSquareBracket = LO.CPlusPlus14 || 
LO.C2x13
;
694
56
    StringRef AttributeSpelling =
695
56
        DoubleSquareBracket ? 
"[[deprecated]]"47
:
"__attribute__((deprecated))"9
;
696
56
    if (PP) {
697
      // Try to find a replacement macro:
698
      // - In C2x/C++14 we prefer [[deprecated]].
699
      // - If not found or an older C/C++ look for __attribute__((deprecated)).
700
49
      StringRef MacroName;
701
49
      if (DoubleSquareBracket) {
702
40
        TokenValue Tokens[] = {tok::l_square, tok::l_square,
703
40
                               PP->getIdentifierInfo("deprecated"),
704
40
                               tok::r_square, tok::r_square};
705
40
        MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
706
40
        if (!MacroName.empty())
707
3
          AttributeSpelling = MacroName;
708
40
      }
709
710
49
      if (MacroName.empty()) {
711
46
        TokenValue Tokens[] = {
712
46
            tok::kw___attribute, tok::l_paren,
713
46
            tok::l_paren,        PP->getIdentifierInfo("deprecated"),
714
46
            tok::r_paren,        tok::r_paren};
715
46
        StringRef MacroName =
716
46
            PP->getLastMacroWithSpelling(FD->getLocation(), Tokens);
717
46
        if (!MacroName.empty())
718
4
          AttributeSpelling = MacroName;
719
46
      }
720
49
    }
721
722
56
    SmallString<64> TextToInsert = AttributeSpelling;
723
56
    TextToInsert += " ";
724
56
    SourceLocation Loc = FD->getSourceRange().getBegin();
725
56
    Diag(Loc, diag::note_add_deprecation_attr)
726
56
        << FixItHint::CreateInsertion(Loc, TextToInsert);
727
56
  }
728
60
}
729
730
1.70k
void Sema::resolveParamCommandIndexes(const FullComment *FC) {
731
1.70k
  if (!involvesFunctionType()) {
732
    // We already warned that \\param commands are not attached to a function
733
    // decl.
734
726
    return;
735
726
  }
736
737
977
  SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
738
739
  // Comment AST nodes that correspond to \c ParamVars for which we have
740
  // found a \\param command or NULL if no documentation was found so far.
741
977
  SmallVector<ParamCommandComment *, 8> ParamVarDocs;
742
743
977
  ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
744
977
  ParamVarDocs.resize(ParamVars.size(), nullptr);
745
746
  // First pass over all \\param commands: resolve all parameter names.
747
977
  for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
748
3.33k
       I != E; 
++I2.35k
) {
749
2.35k
    ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
750
2.35k
    if (!PCC || 
!PCC->hasParamName()461
)
751
1.90k
      continue;
752
453
    StringRef ParamName = PCC->getParamNameAsWritten();
753
754
    // Check that referenced parameter name is in the function decl.
755
453
    const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
756
453
                                                                ParamVars);
757
453
    if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) {
758
38
      PCC->setIsVarArgParam();
759
38
      continue;
760
38
    }
761
415
    if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
762
147
      UnresolvedParamCommands.push_back(PCC);
763
147
      continue;
764
147
    }
765
268
    PCC->setParamIndex(ResolvedParamIndex);
766
268
    if (ParamVarDocs[ResolvedParamIndex]) {
767
6
      SourceRange ArgRange = PCC->getParamNameRange();
768
6
      Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
769
6
        << ParamName << ArgRange;
770
6
      ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
771
6
      Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
772
6
        << PrevCommand->getParamNameRange();
773
6
    }
774
268
    ParamVarDocs[ResolvedParamIndex] = PCC;
775
268
  }
776
777
  // Find parameter declarations that have no corresponding \\param.
778
977
  SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
779
1.78k
  for (unsigned i = 0, e = ParamVarDocs.size(); i != e; 
++i803
) {
780
803
    if (!ParamVarDocs[i])
781
541
      OrphanedParamDecls.push_back(ParamVars[i]);
782
803
  }
783
784
  // Second pass over unresolved \\param commands: do typo correction.
785
  // Suggest corrections from a set of parameter declarations that have no
786
  // corresponding \\param.
787
1.12k
  for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; 
++i147
) {
788
147
    const ParamCommandComment *PCC = UnresolvedParamCommands[i];
789
790
147
    SourceRange ArgRange = PCC->getParamNameRange();
791
147
    StringRef ParamName = PCC->getParamNameAsWritten();
792
147
    Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
793
147
      << ParamName << ArgRange;
794
795
    // All parameters documented -- can't suggest a correction.
796
147
    if (OrphanedParamDecls.size() == 0)
797
39
      continue;
798
799
108
    unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
800
108
    if (OrphanedParamDecls.size() == 1) {
801
      // If one parameter is not documented then that parameter is the only
802
      // possible suggestion.
803
91
      CorrectedParamIndex = 0;
804
91
    } else {
805
      // Do typo correction.
806
17
      CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
807
17
                                                          OrphanedParamDecls);
808
17
    }
809
108
    if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
810
96
      const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
811
96
      if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
812
92
        Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
813
92
          << CorrectedII->getName()
814
92
          << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
815
96
    }
816
108
  }
817
977
}
818
819
2.46k
bool Sema::involvesFunctionType() {
820
2.46k
  if (!ThisDeclInfo)
821
102
    return false;
822
2.36k
  if (!ThisDeclInfo->IsFilled)
823
1.27k
    inspectThisDecl();
824
2.36k
  return ThisDeclInfo->involvesFunctionType();
825
2.46k
}
826
827
19
bool Sema::isFunctionDecl() {
828
19
  if (!ThisDeclInfo)
829
0
    return false;
830
19
  if (!ThisDeclInfo->IsFilled)
831
15
    inspectThisDecl();
832
19
  return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
833
19
}
834
835
11
bool Sema::isAnyFunctionDecl() {
836
11
  return isFunctionDecl() && 
ThisDeclInfo->CurrentDecl8
&&
837
11
         
isa<FunctionDecl>(ThisDeclInfo->CurrentDecl)8
;
838
11
}
839
840
50
bool Sema::isFunctionOrMethodVariadic() {
841
50
  if (!ThisDeclInfo)
842
0
    return false;
843
50
  if (!ThisDeclInfo->IsFilled)
844
0
    inspectThisDecl();
845
50
  return ThisDeclInfo->IsVariadic;
846
50
}
847
848
8
bool Sema::isObjCMethodDecl() {
849
8
  return isFunctionDecl() && 
ThisDeclInfo->CurrentDecl2
&&
850
8
         
isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)2
;
851
8
}
852
853
3
bool Sema::isFunctionPointerVarDecl() {
854
3
  if (!ThisDeclInfo)
855
0
    return false;
856
3
  if (!ThisDeclInfo->IsFilled)
857
3
    inspectThisDecl();
858
3
  if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) {
859
0
    if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) {
860
0
      QualType QT = VD->getType();
861
0
      return QT->isFunctionPointerType();
862
0
    }
863
0
  }
864
3
  return false;
865
3
}
866
867
259
bool Sema::isObjCPropertyDecl() {
868
259
  if (!ThisDeclInfo)
869
0
    return false;
870
259
  if (!ThisDeclInfo->IsFilled)
871
151
    inspectThisDecl();
872
259
  return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty;
873
259
}
874
875
406
bool Sema::isTemplateOrSpecialization() {
876
406
  if (!ThisDeclInfo)
877
9
    return false;
878
397
  if (!ThisDeclInfo->IsFilled)
879
137
    inspectThisDecl();
880
397
  return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
881
406
}
882
883
4
bool Sema::isRecordLikeDecl() {
884
4
  if (!ThisDeclInfo)
885
0
    return false;
886
4
  if (!ThisDeclInfo->IsFilled)
887
0
    inspectThisDecl();
888
4
  return isUnionDecl() || isClassOrStructDecl() || isObjCInterfaceDecl() ||
889
4
         isObjCProtocolDecl();
890
4
}
891
892
10
bool Sema::isUnionDecl() {
893
10
  if (!ThisDeclInfo)
894
0
    return false;
895
10
  if (!ThisDeclInfo->IsFilled)
896
6
    inspectThisDecl();
897
10
  if (const RecordDecl *RD =
898
10
        dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl))
899
6
    return RD->isUnion();
900
4
  return false;
901
10
}
902
35
static bool isClassOrStructDeclImpl(const Decl *D) {
903
35
  if (auto *record = dyn_cast_or_null<RecordDecl>(D))
904
20
    return !record->isUnion();
905
906
15
  return false;
907
35
}
908
909
4
bool Sema::isClassOrStructDecl() {
910
4
  if (!ThisDeclInfo)
911
0
    return false;
912
4
  if (!ThisDeclInfo->IsFilled)
913
0
    inspectThisDecl();
914
915
4
  if (!ThisDeclInfo->CurrentDecl)
916
0
    return false;
917
918
4
  return isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl);
919
4
}
920
921
29
bool Sema::isClassOrStructOrTagTypedefDecl() {
922
29
  if (!ThisDeclInfo)
923
0
    return false;
924
29
  if (!ThisDeclInfo->IsFilled)
925
27
    inspectThisDecl();
926
927
29
  if (!ThisDeclInfo->CurrentDecl)
928
0
    return false;
929
930
29
  if (isClassOrStructDeclImpl(ThisDeclInfo->CurrentDecl))
931
15
    return true;
932
933
14
  if (auto *ThisTypedefDecl = dyn_cast<TypedefDecl>(ThisDeclInfo->CurrentDecl)) {
934
2
    auto UnderlyingType = ThisTypedefDecl->getUnderlyingType();
935
2
    if (auto ThisElaboratedType = dyn_cast<ElaboratedType>(UnderlyingType)) {
936
2
      auto DesugaredType = ThisElaboratedType->desugar();
937
2
      if (auto *DesugaredTypePtr = DesugaredType.getTypePtrOrNull()) {
938
2
        if (auto *ThisRecordType = dyn_cast<RecordType>(DesugaredTypePtr)) {
939
2
          return isClassOrStructDeclImpl(ThisRecordType->getAsRecordDecl());
940
2
        }
941
2
      }
942
2
    }
943
2
  }
944
945
12
  return false;
946
14
}
947
948
7
bool Sema::isClassTemplateDecl() {
949
7
  if (!ThisDeclInfo)
950
0
    return false;
951
7
  if (!ThisDeclInfo->IsFilled)
952
0
    inspectThisDecl();
953
7
  return ThisDeclInfo->CurrentDecl &&
954
7
          (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl));
955
7
}
956
957
6
bool Sema::isFunctionTemplateDecl() {
958
6
  if (!ThisDeclInfo)
959
0
    return false;
960
6
  if (!ThisDeclInfo->IsFilled)
961
0
    inspectThisDecl();
962
6
  return ThisDeclInfo->CurrentDecl &&
963
6
         (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl));
964
6
}
965
966
17
bool Sema::isObjCInterfaceDecl() {
967
17
  if (!ThisDeclInfo)
968
0
    return false;
969
17
  if (!ThisDeclInfo->IsFilled)
970
7
    inspectThisDecl();
971
17
  return ThisDeclInfo->CurrentDecl &&
972
17
         isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl);
973
17
}
974
975
10
bool Sema::isObjCProtocolDecl() {
976
10
  if (!ThisDeclInfo)
977
0
    return false;
978
10
  if (!ThisDeclInfo->IsFilled)
979
6
    inspectThisDecl();
980
10
  return ThisDeclInfo->CurrentDecl &&
981
10
         isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl);
982
10
}
983
984
977
ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
985
977
  if (!ThisDeclInfo->IsFilled)
986
0
    inspectThisDecl();
987
977
  return ThisDeclInfo->ParamVars;
988
977
}
989
990
1.62k
void Sema::inspectThisDecl() {
991
1.62k
  ThisDeclInfo->fill();
992
1.62k
}
993
994
unsigned Sema::resolveParmVarReference(StringRef Name,
995
453
                                       ArrayRef<const ParmVarDecl *> ParamVars) {
996
744
  for (unsigned i = 0, e = ParamVars.size(); i != e; 
++i291
) {
997
559
    const IdentifierInfo *II = ParamVars[i]->getIdentifier();
998
559
    if (II && 
II->getName() == Name555
)
999
268
      return i;
1000
559
  }
1001
185
  if (Name == "..." && 
isFunctionOrMethodVariadic()50
)
1002
38
    return ParamCommandComment::VarArgParamIndex;
1003
147
  return ParamCommandComment::InvalidParamIndex;
1004
185
}
1005
1006
namespace {
1007
class SimpleTypoCorrector {
1008
  const NamedDecl *BestDecl;
1009
1010
  StringRef Typo;
1011
  const unsigned MaxEditDistance;
1012
1013
  unsigned BestEditDistance;
1014
  unsigned BestIndex;
1015
  unsigned NextIndex;
1016
1017
public:
1018
  explicit SimpleTypoCorrector(StringRef Typo)
1019
      : BestDecl(nullptr), Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
1020
28
        BestEditDistance(MaxEditDistance + 1), BestIndex(0), NextIndex(0) {}
1021
1022
  void addDecl(const NamedDecl *ND);
1023
1024
33
  const NamedDecl *getBestDecl() const {
1025
33
    if (BestEditDistance > MaxEditDistance)
1026
16
      return nullptr;
1027
1028
17
    return BestDecl;
1029
33
  }
1030
1031
5
  unsigned getBestDeclIndex() const {
1032
5
    assert(getBestDecl());
1033
0
    return BestIndex;
1034
5
  }
1035
};
1036
1037
59
void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
1038
59
  unsigned CurrIndex = NextIndex++;
1039
1040
59
  const IdentifierInfo *II = ND->getIdentifier();
1041
59
  if (!II)
1042
0
    return;
1043
1044
59
  StringRef Name = II->getName();
1045
59
  unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
1046
59
  if (MinPossibleEditDistance > 0 &&
1047
59
      
Typo.size() / MinPossibleEditDistance < 320
)
1048
15
    return;
1049
1050
44
  unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
1051
44
  if (EditDistance < BestEditDistance) {
1052
12
    BestEditDistance = EditDistance;
1053
12
    BestDecl = ND;
1054
12
    BestIndex = CurrIndex;
1055
12
  }
1056
44
}
1057
} // end anonymous namespace
1058
1059
unsigned Sema::correctTypoInParmVarReference(
1060
                                    StringRef Typo,
1061
17
                                    ArrayRef<const ParmVarDecl *> ParamVars) {
1062
17
  SimpleTypoCorrector Corrector(Typo);
1063
51
  for (unsigned i = 0, e = ParamVars.size(); i != e; 
++i34
)
1064
34
    Corrector.addDecl(ParamVars[i]);
1065
17
  if (Corrector.getBestDecl())
1066
5
    return Corrector.getBestDeclIndex();
1067
12
  else
1068
12
    return ParamCommandComment::InvalidParamIndex;
1069
17
}
1070
1071
namespace {
1072
bool ResolveTParamReferenceHelper(
1073
                            StringRef Name,
1074
                            const TemplateParameterList *TemplateParameters,
1075
202
                            SmallVectorImpl<unsigned> *Position) {
1076
291
  for (unsigned i = 0, e = TemplateParameters->size(); i != e; 
++i89
) {
1077
240
    const NamedDecl *Param = TemplateParameters->getParam(i);
1078
240
    const IdentifierInfo *II = Param->getIdentifier();
1079
240
    if (II && II->getName() == Name) {
1080
121
      Position->push_back(i);
1081
121
      return true;
1082
121
    }
1083
1084
119
    if (const TemplateTemplateParmDecl *TTP =
1085
119
            dyn_cast<TemplateTemplateParmDecl>(Param)) {
1086
33
      Position->push_back(i);
1087
33
      if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
1088
33
                                       Position))
1089
30
        return true;
1090
3
      Position->pop_back();
1091
3
    }
1092
119
  }
1093
51
  return false;
1094
202
}
1095
} // end anonymous namespace
1096
1097
bool Sema::resolveTParamReference(
1098
                            StringRef Name,
1099
                            const TemplateParameterList *TemplateParameters,
1100
172
                            SmallVectorImpl<unsigned> *Position) {
1101
172
  Position->clear();
1102
172
  if (!TemplateParameters)
1103
3
    return false;
1104
1105
169
  return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
1106
172
}
1107
1108
namespace {
1109
void CorrectTypoInTParamReferenceHelper(
1110
                            const TemplateParameterList *TemplateParameters,
1111
11
                            SimpleTypoCorrector &Corrector) {
1112
36
  for (unsigned i = 0, e = TemplateParameters->size(); i != e; 
++i25
) {
1113
25
    const NamedDecl *Param = TemplateParameters->getParam(i);
1114
25
    Corrector.addDecl(Param);
1115
1116
25
    if (const TemplateTemplateParmDecl *TTP =
1117
25
            dyn_cast<TemplateTemplateParmDecl>(Param))
1118
0
      CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
1119
0
                                         Corrector);
1120
25
  }
1121
11
}
1122
} // end anonymous namespace
1123
1124
StringRef Sema::correctTypoInTParamReference(
1125
                            StringRef Typo,
1126
11
                            const TemplateParameterList *TemplateParameters) {
1127
11
  SimpleTypoCorrector Corrector(Typo);
1128
11
  CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
1129
11
  if (const NamedDecl *ND = Corrector.getBestDecl()) {
1130
7
    const IdentifierInfo *II = ND->getIdentifier();
1131
7
    assert(II && "SimpleTypoCorrector should not return this decl");
1132
0
    return II->getName();
1133
7
  }
1134
4
  return StringRef();
1135
11
}
1136
1137
InlineCommandComment::RenderKind
1138
84
Sema::getInlineCommandRenderKind(StringRef Name) const {
1139
84
  assert(Traits.getCommandInfo(Name)->IsInlineCommand);
1140
1141
0
  return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
1142
84
      .Case("b", InlineCommandComment::RenderBold)
1143
84
      .Cases("c", "p", InlineCommandComment::RenderMonospaced)
1144
84
      .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
1145
84
      .Case("anchor", InlineCommandComment::RenderAnchor)
1146
84
      .Default(InlineCommandComment::RenderNormal);
1147
84
}
1148
1149
} // end namespace comments
1150
} // end namespace clang