1 //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "clang/AST/CommentSema.h"
11 #include "clang/AST/CommentDiagnostic.h"
12 #include "clang/AST/CommentCommandTraits.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/StringSwitch.h"
18 #include "llvm/ADT/SmallString.h"
24 #include "clang/AST/CommentHTMLTagsProperties.inc"
25 } // unnamed namespace
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(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
34 void Sema::setDecl(const Decl *D) {
38 ThisDeclInfo = new (Allocator) DeclInfo;
39 ThisDeclInfo->CommentDecl = D;
40 ThisDeclInfo->IsFilled = false;
43 ParagraphComment *Sema::actOnParagraphComment(
44 ArrayRef<InlineContentComment *> Content) {
45 return new (Allocator) ParagraphComment(Content);
48 BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
49 SourceLocation LocEnd,
51 return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
54 void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
55 ArrayRef<BlockCommandComment::Argument> Args) {
56 Command->setArgs(Args);
59 void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
60 ParagraphComment *Paragraph) {
61 Command->setParagraph(Paragraph);
62 checkBlockCommandEmptyParagraph(Command);
63 checkBlockCommandDuplicate(Command);
64 checkReturnsCommand(Command);
65 checkDeprecatedCommand(Command);
68 ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
69 SourceLocation LocEnd,
71 ParamCommandComment *Command =
72 new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
74 if (!isFunctionDecl())
75 Diag(Command->getLocation(),
76 diag::warn_doc_param_not_attached_to_a_function_decl)
77 << Command->getCommandNameRange(Traits);
82 void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
83 SourceLocation ArgLocBegin,
84 SourceLocation ArgLocEnd,
86 ParamCommandComment::PassDirection Direction;
87 std::string ArgLower = Arg.lower();
88 // TODO: optimize: lower Name first (need an API in SmallString for that),
89 // after that StringSwitch.
90 if (ArgLower == "[in]")
91 Direction = ParamCommandComment::In;
92 else if (ArgLower == "[out]")
93 Direction = ParamCommandComment::Out;
94 else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
95 Direction = ParamCommandComment::InOut;
98 std::string::iterator O = ArgLower.begin();
99 for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
102 if (C != ' ' && C != '\n' && C != '\r' &&
103 C != '\t' && C != '\v' && C != '\f')
106 ArgLower.resize(O - ArgLower.begin());
108 bool RemovingWhitespaceHelped = false;
109 if (ArgLower == "[in]") {
110 Direction = ParamCommandComment::In;
111 RemovingWhitespaceHelped = true;
112 } else if (ArgLower == "[out]") {
113 Direction = ParamCommandComment::Out;
114 RemovingWhitespaceHelped = true;
115 } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
116 Direction = ParamCommandComment::InOut;
117 RemovingWhitespaceHelped = true;
119 Direction = ParamCommandComment::In;
120 RemovingWhitespaceHelped = false;
123 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
124 if (RemovingWhitespaceHelped)
125 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
127 << FixItHint::CreateReplacement(
129 ParamCommandComment::getDirectionAsString(Direction));
131 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
134 Command->setDirection(Direction, /* Explicit = */ true);
137 void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
138 SourceLocation ArgLocBegin,
139 SourceLocation ArgLocEnd,
141 // Parser will not feed us more arguments than needed.
142 assert(Command->getNumArgs() == 0);
144 if (!Command->isDirectionExplicit()) {
145 // User didn't provide a direction argument.
146 Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
148 typedef BlockCommandComment::Argument Argument;
149 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
152 Command->setArgs(llvm::makeArrayRef(A, 1));
155 void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
156 ParagraphComment *Paragraph) {
157 Command->setParagraph(Paragraph);
158 checkBlockCommandEmptyParagraph(Command);
161 TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
162 SourceLocation LocEnd,
163 unsigned CommandID) {
164 TParamCommandComment *Command =
165 new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
167 if (!isTemplateOrSpecialization())
168 Diag(Command->getLocation(),
169 diag::warn_doc_tparam_not_attached_to_a_template_decl)
170 << Command->getCommandNameRange(Traits);
175 void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
176 SourceLocation ArgLocBegin,
177 SourceLocation ArgLocEnd,
179 // Parser will not feed us more arguments than needed.
180 assert(Command->getNumArgs() == 0);
182 typedef BlockCommandComment::Argument Argument;
183 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
186 Command->setArgs(llvm::makeArrayRef(A, 1));
188 if (!isTemplateOrSpecialization()) {
189 // We already warned that this \\tparam is not attached to a template decl.
193 const TemplateParameterList *TemplateParameters =
194 ThisDeclInfo->TemplateParameters;
195 SmallVector<unsigned, 2> Position;
196 if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
197 Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
198 llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
199 TemplateParameterDocs.find(Arg);
200 if (PrevCommandIt != TemplateParameterDocs.end()) {
201 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
202 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
204 TParamCommandComment *PrevCommand = PrevCommandIt->second;
205 Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
206 << PrevCommand->getParamNameRange();
208 TemplateParameterDocs[Arg] = Command;
212 SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
213 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
216 if (!TemplateParameters || TemplateParameters->size() == 0)
219 StringRef CorrectedName;
220 if (TemplateParameters->size() == 1) {
221 const NamedDecl *Param = TemplateParameters->getParam(0);
222 const IdentifierInfo *II = Param->getIdentifier();
224 CorrectedName = II->getName();
226 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
229 if (!CorrectedName.empty()) {
230 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
232 << FixItHint::CreateReplacement(ArgRange, CorrectedName);
238 void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
239 ParagraphComment *Paragraph) {
240 Command->setParagraph(Paragraph);
241 checkBlockCommandEmptyParagraph(Command);
244 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
245 SourceLocation CommandLocEnd,
246 unsigned CommandID) {
247 ArrayRef<InlineCommandComment::Argument> Args;
248 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
249 return new (Allocator) InlineCommandComment(
253 getInlineCommandRenderKind(CommandName),
257 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
258 SourceLocation CommandLocEnd,
260 SourceLocation ArgLocBegin,
261 SourceLocation ArgLocEnd,
263 typedef InlineCommandComment::Argument Argument;
264 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
267 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
269 return new (Allocator) InlineCommandComment(
273 getInlineCommandRenderKind(CommandName),
274 llvm::makeArrayRef(A, 1));
277 InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
278 SourceLocation LocEnd,
279 StringRef CommandName) {
280 unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
281 return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
284 InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
285 SourceLocation LocEnd,
286 unsigned CommandID) {
287 ArrayRef<InlineCommandComment::Argument> Args;
288 return new (Allocator) InlineCommandComment(
289 LocBegin, LocEnd, CommandID,
290 InlineCommandComment::RenderNormal,
294 TextComment *Sema::actOnText(SourceLocation LocBegin,
295 SourceLocation LocEnd,
297 return new (Allocator) TextComment(LocBegin, LocEnd, Text);
300 VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
301 unsigned CommandID) {
302 StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
303 return new (Allocator) VerbatimBlockComment(
305 Loc.getLocWithOffset(1 + CommandName.size()),
309 VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
311 return new (Allocator) VerbatimBlockLineComment(Loc, Text);
314 void Sema::actOnVerbatimBlockFinish(
315 VerbatimBlockComment *Block,
316 SourceLocation CloseNameLocBegin,
318 ArrayRef<VerbatimBlockLineComment *> Lines) {
319 Block->setCloseName(CloseName, CloseNameLocBegin);
320 Block->setLines(Lines);
323 VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
325 SourceLocation TextBegin,
327 return new (Allocator) VerbatimLineComment(
329 TextBegin.getLocWithOffset(Text.size()),
335 HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
337 return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
340 void Sema::actOnHTMLStartTagFinish(
341 HTMLStartTagComment *Tag,
342 ArrayRef<HTMLStartTagComment::Attribute> Attrs,
343 SourceLocation GreaterLoc,
344 bool IsSelfClosing) {
345 Tag->setAttrs(Attrs);
346 Tag->setGreaterLoc(GreaterLoc);
348 Tag->setSelfClosing();
349 else if (!isHTMLEndTagForbidden(Tag->getTagName()))
350 HTMLOpenTags.push_back(Tag);
353 HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
354 SourceLocation LocEnd,
356 HTMLEndTagComment *HET =
357 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
358 if (isHTMLEndTagForbidden(TagName)) {
359 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
360 << TagName << HET->getSourceRange();
364 bool FoundOpen = false;
365 for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
366 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
368 if ((*I)->getTagName() == TagName) {
374 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
375 << HET->getSourceRange();
379 while (!HTMLOpenTags.empty()) {
380 const HTMLStartTagComment *HST = HTMLOpenTags.back();
381 HTMLOpenTags.pop_back();
382 StringRef LastNotClosedTagName = HST->getTagName();
383 if (LastNotClosedTagName == TagName)
386 if (isHTMLEndTagOptional(LastNotClosedTagName))
389 bool OpenLineInvalid;
390 const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
393 bool CloseLineInvalid;
394 const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
398 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
399 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
400 << HST->getTagName() << HET->getTagName()
401 << HST->getSourceRange() << HET->getSourceRange();
403 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
404 << HST->getTagName() << HET->getTagName()
405 << HST->getSourceRange();
406 Diag(HET->getLocation(), diag::note_doc_html_end_tag)
407 << HET->getSourceRange();
414 FullComment *Sema::actOnFullComment(
415 ArrayRef<BlockContentComment *> Blocks) {
416 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
417 resolveParamCommandIndexes(FC);
421 void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
422 if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
425 ParagraphComment *Paragraph = Command->getParagraph();
426 if (Paragraph->isWhitespace()) {
427 SourceLocation DiagLoc;
428 if (Command->getNumArgs() > 0)
429 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
430 if (!DiagLoc.isValid())
431 DiagLoc = Command->getCommandNameRange(Traits).getEnd();
432 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
433 << Command->getCommandName(Traits)
434 << Command->getSourceRange();
438 void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
439 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
441 if (isFunctionDecl()) {
442 if (ThisDeclInfo->ResultType->isVoidType()) {
444 switch (ThisDeclInfo->CommentDecl->getKind()) {
446 if (ThisDeclInfo->IsObjCMethod)
451 case Decl::CXXConstructor:
454 case Decl::CXXDestructor:
458 Diag(Command->getLocation(),
459 diag::warn_doc_returns_attached_to_a_void_function)
460 << Command->getCommandName(Traits)
462 << Command->getSourceRange();
466 Diag(Command->getLocation(),
467 diag::warn_doc_returns_not_attached_to_a_function_decl)
468 << Command->getCommandName(Traits)
469 << Command->getSourceRange();
472 void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
473 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
474 const BlockCommandComment *PrevCommand = NULL;
475 if (Info->IsBriefCommand) {
477 BriefCommand = Command;
480 PrevCommand = BriefCommand;
481 } else if (Info->IsReturnsCommand) {
482 if (!ReturnsCommand) {
483 ReturnsCommand = Command;
486 PrevCommand = ReturnsCommand;
488 // We don't want to check this command for duplicates.
491 StringRef CommandName = Command->getCommandName(Traits);
492 StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
493 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
495 << Command->getSourceRange();
496 if (CommandName == PrevCommandName)
497 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
499 << PrevCommand->getSourceRange();
501 Diag(PrevCommand->getLocation(),
502 diag::note_doc_block_command_previous_alias)
507 void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) {
508 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand)
511 const Decl *D = ThisDeclInfo->CommentDecl;
515 if (D->hasAttr<DeprecatedAttr>() ||
516 D->hasAttr<AvailabilityAttr>() ||
517 D->hasAttr<UnavailableAttr>())
520 Diag(Command->getLocation(),
521 diag::warn_doc_deprecated_not_sync)
522 << Command->getSourceRange();
524 // Try to emit a fixit with a deprecation attribute.
525 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
526 // Don't emit a Fix-It for non-member function definitions. GCC does not
527 // accept attributes on them.
528 const DeclContext *Ctx = FD->getDeclContext();
529 if ((!Ctx || !Ctx->isRecord()) &&
530 FD->doesThisDeclarationHaveABody())
533 StringRef AttributeSpelling = "__attribute__((deprecated))";
535 TokenValue Tokens[] = {
536 tok::kw___attribute, tok::l_paren, tok::l_paren,
537 PP->getIdentifierInfo("deprecated"),
538 tok::r_paren, tok::r_paren
540 StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(),
542 if (!MacroName.empty())
543 AttributeSpelling = MacroName;
546 SmallString<64> TextToInsert(" ");
547 TextToInsert += AttributeSpelling;
548 Diag(FD->getLocEnd(),
549 diag::note_add_deprecation_attr)
550 << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1),
555 void Sema::resolveParamCommandIndexes(const FullComment *FC) {
556 if (!isFunctionDecl()) {
557 // We already warned that \\param commands are not attached to a function
562 llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
564 // Comment AST nodes that correspond to \c ParamVars for which we have
565 // found a \\param command or NULL if no documentation was found so far.
566 llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
568 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
569 ParamVarDocs.resize(ParamVars.size(), NULL);
571 // First pass over all \\param commands: resolve all parameter names.
572 for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
574 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
575 if (!PCC || !PCC->hasParamName())
577 StringRef ParamName = PCC->getParamNameAsWritten();
579 // Check that referenced parameter name is in the function decl.
580 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
582 if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
583 UnresolvedParamCommands.push_back(PCC);
586 PCC->setParamIndex(ResolvedParamIndex);
587 if (ParamVarDocs[ResolvedParamIndex]) {
588 SourceRange ArgRange = PCC->getParamNameRange();
589 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
590 << ParamName << ArgRange;
591 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
592 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
593 << PrevCommand->getParamNameRange();
595 ParamVarDocs[ResolvedParamIndex] = PCC;
598 // Find parameter declarations that have no corresponding \\param.
599 llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
600 for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
601 if (!ParamVarDocs[i])
602 OrphanedParamDecls.push_back(ParamVars[i]);
605 // Second pass over unresolved \\param commands: do typo correction.
606 // Suggest corrections from a set of parameter declarations that have no
607 // corresponding \\param.
608 for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
609 const ParamCommandComment *PCC = UnresolvedParamCommands[i];
611 SourceRange ArgRange = PCC->getParamNameRange();
612 StringRef ParamName = PCC->getParamNameAsWritten();
613 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
614 << ParamName << ArgRange;
616 // All parameters documented -- can't suggest a correction.
617 if (OrphanedParamDecls.size() == 0)
620 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
621 if (OrphanedParamDecls.size() == 1) {
622 // If one parameter is not documented then that parameter is the only
623 // possible suggestion.
624 CorrectedParamIndex = 0;
626 // Do typo correction.
627 CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
630 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
631 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
632 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
633 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
634 << CorrectedII->getName()
635 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
640 bool Sema::isFunctionDecl() {
643 if (!ThisDeclInfo->IsFilled)
645 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
648 bool Sema::isTemplateOrSpecialization() {
651 if (!ThisDeclInfo->IsFilled)
653 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
656 ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
657 if (!ThisDeclInfo->IsFilled)
659 return ThisDeclInfo->ParamVars;
662 void Sema::inspectThisDecl() {
663 ThisDeclInfo->fill();
666 unsigned Sema::resolveParmVarReference(StringRef Name,
667 ArrayRef<const ParmVarDecl *> ParamVars) {
668 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
669 const IdentifierInfo *II = ParamVars[i]->getIdentifier();
670 if (II && II->getName() == Name)
673 return ParamCommandComment::InvalidParamIndex;
677 class SimpleTypoCorrector {
679 const unsigned MaxEditDistance;
681 const NamedDecl *BestDecl;
682 unsigned BestEditDistance;
687 SimpleTypoCorrector(StringRef Typo) :
688 Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
689 BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
690 BestIndex(0), NextIndex(0)
693 void addDecl(const NamedDecl *ND);
695 const NamedDecl *getBestDecl() const {
696 if (BestEditDistance > MaxEditDistance)
702 unsigned getBestDeclIndex() const {
703 assert(getBestDecl());
708 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
709 unsigned CurrIndex = NextIndex++;
711 const IdentifierInfo *II = ND->getIdentifier();
715 StringRef Name = II->getName();
716 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
717 if (MinPossibleEditDistance > 0 &&
718 Typo.size() / MinPossibleEditDistance < 3)
721 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
722 if (EditDistance < BestEditDistance) {
723 BestEditDistance = EditDistance;
725 BestIndex = CurrIndex;
728 } // unnamed namespace
730 unsigned Sema::correctTypoInParmVarReference(
732 ArrayRef<const ParmVarDecl *> ParamVars) {
733 SimpleTypoCorrector Corrector(Typo);
734 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
735 Corrector.addDecl(ParamVars[i]);
736 if (Corrector.getBestDecl())
737 return Corrector.getBestDeclIndex();
739 return ParamCommandComment::InvalidParamIndex;
743 bool ResolveTParamReferenceHelper(
745 const TemplateParameterList *TemplateParameters,
746 SmallVectorImpl<unsigned> *Position) {
747 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
748 const NamedDecl *Param = TemplateParameters->getParam(i);
749 const IdentifierInfo *II = Param->getIdentifier();
750 if (II && II->getName() == Name) {
751 Position->push_back(i);
755 if (const TemplateTemplateParmDecl *TTP =
756 dyn_cast<TemplateTemplateParmDecl>(Param)) {
757 Position->push_back(i);
758 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
761 Position->pop_back();
766 } // unnamed namespace
768 bool Sema::resolveTParamReference(
770 const TemplateParameterList *TemplateParameters,
771 SmallVectorImpl<unsigned> *Position) {
773 if (!TemplateParameters)
776 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
780 void CorrectTypoInTParamReferenceHelper(
781 const TemplateParameterList *TemplateParameters,
782 SimpleTypoCorrector &Corrector) {
783 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
784 const NamedDecl *Param = TemplateParameters->getParam(i);
785 Corrector.addDecl(Param);
787 if (const TemplateTemplateParmDecl *TTP =
788 dyn_cast<TemplateTemplateParmDecl>(Param))
789 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
793 } // unnamed namespace
795 StringRef Sema::correctTypoInTParamReference(
797 const TemplateParameterList *TemplateParameters) {
798 SimpleTypoCorrector Corrector(Typo);
799 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
800 if (const NamedDecl *ND = Corrector.getBestDecl()) {
801 const IdentifierInfo *II = ND->getIdentifier();
802 assert(II && "SimpleTypoCorrector should not return this decl");
803 return II->getName();
808 InlineCommandComment::RenderKind
809 Sema::getInlineCommandRenderKind(StringRef Name) const {
810 assert(Traits.getCommandInfo(Name)->IsInlineCommand);
812 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
813 .Case("b", InlineCommandComment::RenderBold)
814 .Cases("c", "p", InlineCommandComment::RenderMonospaced)
815 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
816 .Default(InlineCommandComment::RenderNormal);
819 } // end namespace comments
820 } // end namespace clang