Coverage Report

Created: 2019-07-24 05:18

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