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