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