Clang Project

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