1 //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
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 "llvm/ADT/StringSwitch.h"
17 
18 namespace clang {
19 namespace comments {
20 
21 namespace {
22 #include "clang/AST/CommentHTMLTagsProperties.inc"
23 } // unnamed namespace
24 
25 Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr,
26            DiagnosticsEngine &Diags, CommandTraits &Traits) :
27     Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits),
28     ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) {
29 }
30 
31 void Sema::setDecl(const Decl *D) {
32   if (!D)
33     return;
34 
35   ThisDeclInfo = new (Allocator) DeclInfo;
36   ThisDeclInfo->ThisDecl = D;
37   ThisDeclInfo->IsFilled = false;
38 }
39 
40 ParagraphComment *Sema::actOnParagraphComment(
41                               ArrayRef<InlineContentComment *> Content) {
42   return new (Allocator) ParagraphComment(Content);
43 }
44 
45 BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin,
46                                                   SourceLocation LocEnd,
47                                                   unsigned CommandID) {
48   return new (Allocator) BlockCommandComment(LocBegin, LocEnd, CommandID);
49 }
50 
51 void Sema::actOnBlockCommandArgs(BlockCommandComment *Command,
52                                  ArrayRef<BlockCommandComment::Argument> Args) {
53   Command->setArgs(Args);
54 }
55 
56 void Sema::actOnBlockCommandFinish(BlockCommandComment *Command,
57                                    ParagraphComment *Paragraph) {
58   Command->setParagraph(Paragraph);
59   checkBlockCommandEmptyParagraph(Command);
60   checkBlockCommandDuplicate(Command);
61   checkReturnsCommand(Command);
62 }
63 
64 ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin,
65                                                   SourceLocation LocEnd,
66                                                   unsigned CommandID) {
67   ParamCommandComment *Command =
68       new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID);
69 
70   if (!isFunctionDecl())
71     Diag(Command->getLocation(),
72          diag::warn_doc_param_not_attached_to_a_function_decl)
73       << Command->getCommandNameRange(Traits);
74 
75   return Command;
76 }
77 
78 void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command,
79                                          SourceLocation ArgLocBegin,
80                                          SourceLocation ArgLocEnd,
81                                          StringRef Arg) {
82   ParamCommandComment::PassDirection Direction;
83   std::string ArgLower = Arg.lower();
84   // TODO: optimize: lower Name first (need an API in SmallString for that),
85   // after that StringSwitch.
86   if (ArgLower == "[in]")
87     Direction = ParamCommandComment::In;
88   else if (ArgLower == "[out]")
89     Direction = ParamCommandComment::Out;
90   else if (ArgLower == "[in,out]" || ArgLower == "[out,in]")
91     Direction = ParamCommandComment::InOut;
92   else {
93     // Remove spaces.
94     std::string::iterator O = ArgLower.begin();
95     for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end();
96          I != E; ++I) {
97       const char C = *I;
98       if (C != ' ' && C != '\n' && C != '\r' &&
99           C != '\t' && C != '\v' && C != '\f')
100         *O++ = C;
101     }
102     ArgLower.resize(O - ArgLower.begin());
103 
104     bool RemovingWhitespaceHelped = false;
105     if (ArgLower == "[in]") {
106       Direction = ParamCommandComment::In;
107       RemovingWhitespaceHelped = true;
108     } else if (ArgLower == "[out]") {
109       Direction = ParamCommandComment::Out;
110       RemovingWhitespaceHelped = true;
111     } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") {
112       Direction = ParamCommandComment::InOut;
113       RemovingWhitespaceHelped = true;
114     } else {
115       Direction = ParamCommandComment::In;
116       RemovingWhitespaceHelped = false;
117     }
118 
119     SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
120     if (RemovingWhitespaceHelped)
121       Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction)
122         << ArgRange
123         << FixItHint::CreateReplacement(
124                           ArgRange,
125                           ParamCommandComment::getDirectionAsString(Direction));
126     else
127       Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction)
128         << ArgRange;
129   }
130   Command->setDirection(Direction, /* Explicit = */ true);
131 }
132 
133 void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
134                                          SourceLocation ArgLocBegin,
135                                          SourceLocation ArgLocEnd,
136                                          StringRef Arg) {
137   // Parser will not feed us more arguments than needed.
138   assert(Command->getNumArgs() == 0);
139 
140   if (!Command->isDirectionExplicit()) {
141     // User didn't provide a direction argument.
142     Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
143   }
144   typedef BlockCommandComment::Argument Argument;
145   Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
146                                                      ArgLocEnd),
147                                          Arg);
148   Command->setArgs(llvm::makeArrayRef(A, 1));
149 }
150 
151 void Sema::actOnParamCommandFinish(ParamCommandComment *Command,
152                                    ParagraphComment *Paragraph) {
153   Command->setParagraph(Paragraph);
154   checkBlockCommandEmptyParagraph(Command);
155 }
156 
157 TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin,
158                                                     SourceLocation LocEnd,
159                                                     unsigned CommandID) {
160   TParamCommandComment *Command =
161       new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID);
162 
163   if (!isTemplateOrSpecialization())
164     Diag(Command->getLocation(),
165          diag::warn_doc_tparam_not_attached_to_a_template_decl)
166       << Command->getCommandNameRange(Traits);
167 
168   return Command;
169 }
170 
171 void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
172                                           SourceLocation ArgLocBegin,
173                                           SourceLocation ArgLocEnd,
174                                           StringRef Arg) {
175   // Parser will not feed us more arguments than needed.
176   assert(Command->getNumArgs() == 0);
177 
178   typedef BlockCommandComment::Argument Argument;
179   Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
180                                                      ArgLocEnd),
181                                          Arg);
182   Command->setArgs(llvm::makeArrayRef(A, 1));
183 
184   if (!isTemplateOrSpecialization()) {
185     // We already warned that this \\tparam is not attached to a template decl.
186     return;
187   }
188 
189   const TemplateParameterList *TemplateParameters =
190       ThisDeclInfo->TemplateParameters;
191   SmallVector<unsigned, 2> Position;
192   if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
193     Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
194     llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
195         TemplateParameterDocs.find(Arg);
196     if (PrevCommandIt != TemplateParameterDocs.end()) {
197       SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
198       Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
199         << Arg << ArgRange;
200       TParamCommandComment *PrevCommand = PrevCommandIt->second;
201       Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
202         << PrevCommand->getParamNameRange();
203     }
204     TemplateParameterDocs[Arg] = Command;
205     return;
206   }
207 
208   SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
209   Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
210     << Arg << ArgRange;
211 
212   if (!TemplateParameters || TemplateParameters->size() == 0)
213     return;
214 
215   StringRef CorrectedName;
216   if (TemplateParameters->size() == 1) {
217     const NamedDecl *Param = TemplateParameters->getParam(0);
218     const IdentifierInfo *II = Param->getIdentifier();
219     if (II)
220       CorrectedName = II->getName();
221   } else {
222     CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
223   }
224 
225   if (!CorrectedName.empty()) {
226     Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
227       << CorrectedName
228       << FixItHint::CreateReplacement(ArgRange, CorrectedName);
229   }
230 
231   return;
232 }
233 
234 void Sema::actOnTParamCommandFinish(TParamCommandComment *Command,
235                                     ParagraphComment *Paragraph) {
236   Command->setParagraph(Paragraph);
237   checkBlockCommandEmptyParagraph(Command);
238 }
239 
240 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
241                                                SourceLocation CommandLocEnd,
242                                                unsigned CommandID) {
243   ArrayRef<InlineCommandComment::Argument> Args;
244   StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
245   return new (Allocator) InlineCommandComment(
246                                   CommandLocBegin,
247                                   CommandLocEnd,
248                                   CommandID,
249                                   getInlineCommandRenderKind(CommandName),
250                                   Args);
251 }
252 
253 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
254                                                SourceLocation CommandLocEnd,
255                                                unsigned CommandID,
256                                                SourceLocation ArgLocBegin,
257                                                SourceLocation ArgLocEnd,
258                                                StringRef Arg) {
259   typedef InlineCommandComment::Argument Argument;
260   Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
261                                                      ArgLocEnd),
262                                          Arg);
263   StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
264 
265   return new (Allocator) InlineCommandComment(
266                                   CommandLocBegin,
267                                   CommandLocEnd,
268                                   CommandID,
269                                   getInlineCommandRenderKind(CommandName),
270                                   llvm::makeArrayRef(A, 1));
271 }
272 
273 InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
274                                                 SourceLocation LocEnd,
275                                                 StringRef CommandName) {
276   unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID();
277   return actOnUnknownCommand(LocBegin, LocEnd, CommandID);
278 }
279 
280 InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin,
281                                                 SourceLocation LocEnd,
282                                                 unsigned CommandID) {
283   ArrayRef<InlineCommandComment::Argument> Args;
284   return new (Allocator) InlineCommandComment(
285                                   LocBegin, LocEnd, CommandID,
286                                   InlineCommandComment::RenderNormal,
287                                   Args);
288 }
289 
290 TextComment *Sema::actOnText(SourceLocation LocBegin,
291                              SourceLocation LocEnd,
292                              StringRef Text) {
293   return new (Allocator) TextComment(LocBegin, LocEnd, Text);
294 }
295 
296 VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc,
297                                                     unsigned CommandID) {
298   StringRef CommandName = Traits.getCommandInfo(CommandID)->Name;
299   return new (Allocator) VerbatimBlockComment(
300                                   Loc,
301                                   Loc.getLocWithOffset(1 + CommandName.size()),
302                                   CommandID);
303 }
304 
305 VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc,
306                                                        StringRef Text) {
307   return new (Allocator) VerbatimBlockLineComment(Loc, Text);
308 }
309 
310 void Sema::actOnVerbatimBlockFinish(
311                             VerbatimBlockComment *Block,
312                             SourceLocation CloseNameLocBegin,
313                             StringRef CloseName,
314                             ArrayRef<VerbatimBlockLineComment *> Lines) {
315   Block->setCloseName(CloseName, CloseNameLocBegin);
316   Block->setLines(Lines);
317 }
318 
319 VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin,
320                                              unsigned CommandID,
321                                              SourceLocation TextBegin,
322                                              StringRef Text) {
323   return new (Allocator) VerbatimLineComment(
324                               LocBegin,
325                               TextBegin.getLocWithOffset(Text.size()),
326                               CommandID,
327                               TextBegin,
328                               Text);
329 }
330 
331 HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin,
332                                                   StringRef TagName) {
333   return new (Allocator) HTMLStartTagComment(LocBegin, TagName);
334 }
335 
336 void Sema::actOnHTMLStartTagFinish(
337                               HTMLStartTagComment *Tag,
338                               ArrayRef<HTMLStartTagComment::Attribute> Attrs,
339                               SourceLocation GreaterLoc,
340                               bool IsSelfClosing) {
341   Tag->setAttrs(Attrs);
342   Tag->setGreaterLoc(GreaterLoc);
343   if (IsSelfClosing)
344     Tag->setSelfClosing();
345   else if (!isHTMLEndTagForbidden(Tag->getTagName()))
346     HTMLOpenTags.push_back(Tag);
347 }
348 
349 HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin,
350                                          SourceLocation LocEnd,
351                                          StringRef TagName) {
352   HTMLEndTagComment *HET =
353       new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName);
354   if (isHTMLEndTagForbidden(TagName)) {
355     Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden)
356       << TagName << HET->getSourceRange();
357     return HET;
358   }
359 
360   bool FoundOpen = false;
361   for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator
362        I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend();
363        I != E; ++I) {
364     if ((*I)->getTagName() == TagName) {
365       FoundOpen = true;
366       break;
367     }
368   }
369   if (!FoundOpen) {
370     Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced)
371       << HET->getSourceRange();
372     return HET;
373   }
374 
375   while (!HTMLOpenTags.empty()) {
376     const HTMLStartTagComment *HST = HTMLOpenTags.back();
377     HTMLOpenTags.pop_back();
378     StringRef LastNotClosedTagName = HST->getTagName();
379     if (LastNotClosedTagName == TagName)
380       break;
381 
382     if (isHTMLEndTagOptional(LastNotClosedTagName))
383       continue;
384 
385     bool OpenLineInvalid;
386     const unsigned OpenLine = SourceMgr.getPresumedLineNumber(
387                                                 HST->getLocation(),
388                                                 &OpenLineInvalid);
389     bool CloseLineInvalid;
390     const unsigned CloseLine = SourceMgr.getPresumedLineNumber(
391                                                 HET->getLocation(),
392                                                 &CloseLineInvalid);
393 
394     if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine)
395       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
396         << HST->getTagName() << HET->getTagName()
397         << HST->getSourceRange() << HET->getSourceRange();
398     else {
399       Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch)
400         << HST->getTagName() << HET->getTagName()
401         << HST->getSourceRange();
402       Diag(HET->getLocation(), diag::note_doc_html_end_tag)
403         << HET->getSourceRange();
404     }
405   }
406 
407   return HET;
408 }
409 
410 FullComment *Sema::actOnFullComment(
411                               ArrayRef<BlockContentComment *> Blocks) {
412   FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo);
413   resolveParamCommandIndexes(FC);
414   return FC;
415 }
416 
417 void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) {
418   if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed)
419     return;
420 
421   ParagraphComment *Paragraph = Command->getParagraph();
422   if (Paragraph->isWhitespace()) {
423     SourceLocation DiagLoc;
424     if (Command->getNumArgs() > 0)
425       DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd();
426     if (!DiagLoc.isValid())
427       DiagLoc = Command->getCommandNameRange(Traits).getEnd();
428     Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph)
429       << Command->getCommandName(Traits)
430       << Command->getSourceRange();
431   }
432 }
433 
434 void Sema::checkReturnsCommand(const BlockCommandComment *Command) {
435   if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand)
436     return;
437   if (isFunctionDecl()) {
438     if (ThisDeclInfo->ResultType->isVoidType()) {
439       unsigned DiagKind;
440       switch (ThisDeclInfo->ThisDecl->getKind()) {
441       default:
442         if (ThisDeclInfo->IsObjCMethod)
443           DiagKind = 3;
444         else
445           DiagKind = 0;
446         break;
447       case Decl::CXXConstructor:
448         DiagKind = 1;
449         break;
450       case Decl::CXXDestructor:
451         DiagKind = 2;
452         break;
453       }
454       Diag(Command->getLocation(),
455            diag::warn_doc_returns_attached_to_a_void_function)
456         << Command->getCommandName(Traits)
457         << DiagKind
458         << Command->getSourceRange();
459     }
460     return;
461   }
462   Diag(Command->getLocation(),
463        diag::warn_doc_returns_not_attached_to_a_function_decl)
464     << Command->getCommandName(Traits)
465     << Command->getSourceRange();
466 }
467 
468 void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) {
469   const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID());
470   const BlockCommandComment *PrevCommand = NULL;
471   if (Info->IsBriefCommand) {
472     if (!BriefCommand) {
473       BriefCommand = Command;
474       return;
475     }
476     PrevCommand = BriefCommand;
477   } else if (Info->IsReturnsCommand) {
478     if (!ReturnsCommand) {
479       ReturnsCommand = Command;
480       return;
481     }
482     PrevCommand = ReturnsCommand;
483   } else {
484     // We don't want to check this command for duplicates.
485     return;
486   }
487   StringRef CommandName = Command->getCommandName(Traits);
488   StringRef PrevCommandName = PrevCommand->getCommandName(Traits);
489   Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate)
490       << CommandName
491       << Command->getSourceRange();
492   if (CommandName == PrevCommandName)
493     Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous)
494         << PrevCommandName
495         << PrevCommand->getSourceRange();
496   else
497     Diag(PrevCommand->getLocation(),
498          diag::note_doc_block_command_previous_alias)
499         << PrevCommandName
500         << CommandName;
501 }
502 
503 void Sema::resolveParamCommandIndexes(const FullComment *FC) {
504   if (!isFunctionDecl()) {
505     // We already warned that \\param commands are not attached to a function
506     // decl.
507     return;
508   }
509 
510   llvm::SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands;
511 
512   // Comment AST nodes that correspond to \c ParamVars for which we have
513   // found a \\param command or NULL if no documentation was found so far.
514   llvm::SmallVector<ParamCommandComment *, 8> ParamVarDocs;
515 
516   ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();
517   ParamVarDocs.resize(ParamVars.size(), NULL);
518 
519   // First pass over all \\param commands: resolve all parameter names.
520   for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end();
521        I != E; ++I) {
522     ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I);
523     if (!PCC || !PCC->hasParamName())
524       continue;
525     StringRef ParamName = PCC->getParamName();
526 
527     // Check that referenced parameter name is in the function decl.
528     const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName,
529                                                                 ParamVars);
530     if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) {
531       UnresolvedParamCommands.push_back(PCC);
532       continue;
533     }
534     PCC->setParamIndex(ResolvedParamIndex);
535     if (ParamVarDocs[ResolvedParamIndex]) {
536       SourceRange ArgRange = PCC->getParamNameRange();
537       Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate)
538         << ParamName << ArgRange;
539       ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
540       Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
541         << PrevCommand->getParamNameRange();
542     }
543     ParamVarDocs[ResolvedParamIndex] = PCC;
544   }
545 
546   // Find parameter declarations that have no corresponding \\param.
547   llvm::SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls;
548   for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) {
549     if (!ParamVarDocs[i])
550       OrphanedParamDecls.push_back(ParamVars[i]);
551   }
552 
553   // Second pass over unresolved \\param commands: do typo correction.
554   // Suggest corrections from a set of parameter declarations that have no
555   // corresponding \\param.
556   for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) {
557     const ParamCommandComment *PCC = UnresolvedParamCommands[i];
558 
559     SourceRange ArgRange = PCC->getParamNameRange();
560     StringRef ParamName = PCC->getParamName();
561     Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found)
562       << ParamName << ArgRange;
563 
564     // All parameters documented -- can't suggest a correction.
565     if (OrphanedParamDecls.size() == 0)
566       continue;
567 
568     unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
569     if (OrphanedParamDecls.size() == 1) {
570       // If one parameter is not documented then that parameter is the only
571       // possible suggestion.
572       CorrectedParamIndex = 0;
573     } else {
574       // Do typo correction.
575       CorrectedParamIndex = correctTypoInParmVarReference(ParamName,
576                                                           OrphanedParamDecls);
577     }
578     if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
579       const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex];
580       if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
581         Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion)
582           << CorrectedII->getName()
583           << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
584     }
585   }
586 }
587 
588 bool Sema::isFunctionDecl() {
589   if (!ThisDeclInfo)
590     return false;
591   if (!ThisDeclInfo->IsFilled)
592     inspectThisDecl();
593   return ThisDeclInfo->getKind() == DeclInfo::FunctionKind;
594 }
595 
596 bool Sema::isTemplateOrSpecialization() {
597   if (!ThisDeclInfo)
598     return false;
599   if (!ThisDeclInfo->IsFilled)
600     inspectThisDecl();
601   return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate;
602 }
603 
604 ArrayRef<const ParmVarDecl *> Sema::getParamVars() {
605   if (!ThisDeclInfo->IsFilled)
606     inspectThisDecl();
607   return ThisDeclInfo->ParamVars;
608 }
609 
610 void Sema::inspectThisDecl() {
611   ThisDeclInfo->fill();
612 }
613 
614 unsigned Sema::resolveParmVarReference(StringRef Name,
615                                        ArrayRef<const ParmVarDecl *> ParamVars) {
616   for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) {
617     const IdentifierInfo *II = ParamVars[i]->getIdentifier();
618     if (II && II->getName() == Name)
619       return i;
620   }
621   return ParamCommandComment::InvalidParamIndex;
622 }
623 
624 namespace {
625 class SimpleTypoCorrector {
626   StringRef Typo;
627   const unsigned MaxEditDistance;
628 
629   const NamedDecl *BestDecl;
630   unsigned BestEditDistance;
631   unsigned BestIndex;
632   unsigned NextIndex;
633 
634 public:
635   SimpleTypoCorrector(StringRef Typo) :
636       Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3),
637       BestDecl(NULL), BestEditDistance(MaxEditDistance + 1),
638       BestIndex(0), NextIndex(0)
639   { }
640 
641   void addDecl(const NamedDecl *ND);
642 
643   const NamedDecl *getBestDecl() const {
644     if (BestEditDistance > MaxEditDistance)
645       return NULL;
646 
647     return BestDecl;
648   }
649 
650   unsigned getBestDeclIndex() const {
651     assert(getBestDecl());
652     return BestIndex;
653   }
654 };
655 
656 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) {
657   unsigned CurrIndex = NextIndex++;
658 
659   const IdentifierInfo *II = ND->getIdentifier();
660   if (!II)
661     return;
662 
663   StringRef Name = II->getName();
664   unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());
665   if (MinPossibleEditDistance > 0 &&
666       Typo.size() / MinPossibleEditDistance < 3)
667     return;
668 
669   unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);
670   if (EditDistance < BestEditDistance) {
671     BestEditDistance = EditDistance;
672     BestDecl = ND;
673     BestIndex = CurrIndex;
674   }
675 }
676 } // unnamed namespace
677 
678 unsigned Sema::correctTypoInParmVarReference(
679                                     StringRef Typo,
680                                     ArrayRef<const ParmVarDecl *> ParamVars) {
681   SimpleTypoCorrector Corrector(Typo);
682   for (unsigned i = 0, e = ParamVars.size(); i != e; ++i)
683     Corrector.addDecl(ParamVars[i]);
684   if (Corrector.getBestDecl())
685     return Corrector.getBestDeclIndex();
686   else
687     return ParamCommandComment::InvalidParamIndex;
688 }
689 
690 namespace {
691 bool ResolveTParamReferenceHelper(
692                             StringRef Name,
693                             const TemplateParameterList *TemplateParameters,
694                             SmallVectorImpl<unsigned> *Position) {
695   for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
696     const NamedDecl *Param = TemplateParameters->getParam(i);
697     const IdentifierInfo *II = Param->getIdentifier();
698     if (II && II->getName() == Name) {
699       Position->push_back(i);
700       return true;
701     }
702 
703     if (const TemplateTemplateParmDecl *TTP =
704             dyn_cast<TemplateTemplateParmDecl>(Param)) {
705       Position->push_back(i);
706       if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(),
707                                        Position))
708         return true;
709       Position->pop_back();
710     }
711   }
712   return false;
713 }
714 } // unnamed namespace
715 
716 bool Sema::resolveTParamReference(
717                             StringRef Name,
718                             const TemplateParameterList *TemplateParameters,
719                             SmallVectorImpl<unsigned> *Position) {
720   Position->clear();
721   if (!TemplateParameters)
722     return false;
723 
724   return ResolveTParamReferenceHelper(Name, TemplateParameters, Position);
725 }
726 
727 namespace {
728 void CorrectTypoInTParamReferenceHelper(
729                             const TemplateParameterList *TemplateParameters,
730                             SimpleTypoCorrector &Corrector) {
731   for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) {
732     const NamedDecl *Param = TemplateParameters->getParam(i);
733     Corrector.addDecl(Param);
734 
735     if (const TemplateTemplateParmDecl *TTP =
736             dyn_cast<TemplateTemplateParmDecl>(Param))
737       CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(),
738                                          Corrector);
739   }
740 }
741 } // unnamed namespace
742 
743 StringRef Sema::correctTypoInTParamReference(
744                             StringRef Typo,
745                             const TemplateParameterList *TemplateParameters) {
746   SimpleTypoCorrector Corrector(Typo);
747   CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector);
748   if (const NamedDecl *ND = Corrector.getBestDecl()) {
749     const IdentifierInfo *II = ND->getIdentifier();
750     assert(II && "SimpleTypoCorrector should not return this decl");
751     return II->getName();
752   }
753   return StringRef();
754 }
755 
756 InlineCommandComment::RenderKind
757 Sema::getInlineCommandRenderKind(StringRef Name) const {
758   assert(Traits.getCommandInfo(Name)->IsInlineCommand);
759 
760   return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name)
761       .Case("b", InlineCommandComment::RenderBold)
762       .Cases("c", "p", InlineCommandComment::RenderMonospaced)
763       .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized)
764       .Default(InlineCommandComment::RenderNormal);
765 }
766 
767 } // end namespace comments
768 } // end namespace clang
769 
770