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