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