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