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.pop_back_val(); 519 StringRef LastNotClosedTagName = HST->getTagName(); 520 if (LastNotClosedTagName == TagName) 521 break; 522 523 if (isHTMLEndTagOptional(LastNotClosedTagName)) 524 continue; 525 526 bool OpenLineInvalid; 527 const unsigned OpenLine = SourceMgr.getPresumedLineNumber( 528 HST->getLocation(), 529 &OpenLineInvalid); 530 bool CloseLineInvalid; 531 const unsigned CloseLine = SourceMgr.getPresumedLineNumber( 532 HET->getLocation(), 533 &CloseLineInvalid); 534 535 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) 536 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) 537 << HST->getTagName() << HET->getTagName() 538 << HST->getSourceRange() << HET->getSourceRange(); 539 else { 540 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) 541 << HST->getTagName() << HET->getTagName() 542 << HST->getSourceRange(); 543 Diag(HET->getLocation(), diag::note_doc_html_end_tag) 544 << HET->getSourceRange(); 545 } 546 } 547 548 return HET; 549 } 550 551 FullComment *Sema::actOnFullComment( 552 ArrayRef<BlockContentComment *> Blocks) { 553 FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo); 554 resolveParamCommandIndexes(FC); 555 return FC; 556 } 557 558 void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { 559 if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed) 560 return; 561 562 ParagraphComment *Paragraph = Command->getParagraph(); 563 if (Paragraph->isWhitespace()) { 564 SourceLocation DiagLoc; 565 if (Command->getNumArgs() > 0) 566 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd(); 567 if (!DiagLoc.isValid()) 568 DiagLoc = Command->getCommandNameRange(Traits).getEnd(); 569 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) 570 << Command->getCommandMarker() 571 << Command->getCommandName(Traits) 572 << Command->getSourceRange(); 573 } 574 } 575 576 void Sema::checkReturnsCommand(const BlockCommandComment *Command) { 577 if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand) 578 return; 579 if (isFunctionDecl()) { 580 if (ThisDeclInfo->ResultType->isVoidType()) { 581 unsigned DiagKind; 582 switch (ThisDeclInfo->CommentDecl->getKind()) { 583 default: 584 if (ThisDeclInfo->IsObjCMethod) 585 DiagKind = 3; 586 else 587 DiagKind = 0; 588 break; 589 case Decl::CXXConstructor: 590 DiagKind = 1; 591 break; 592 case Decl::CXXDestructor: 593 DiagKind = 2; 594 break; 595 } 596 Diag(Command->getLocation(), 597 diag::warn_doc_returns_attached_to_a_void_function) 598 << Command->getCommandMarker() 599 << Command->getCommandName(Traits) 600 << DiagKind 601 << Command->getSourceRange(); 602 } 603 return; 604 } 605 else if (isObjCPropertyDecl()) 606 return; 607 608 Diag(Command->getLocation(), 609 diag::warn_doc_returns_not_attached_to_a_function_decl) 610 << Command->getCommandMarker() 611 << Command->getCommandName(Traits) 612 << Command->getSourceRange(); 613 } 614 615 void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { 616 const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID()); 617 const BlockCommandComment *PrevCommand = NULL; 618 if (Info->IsBriefCommand) { 619 if (!BriefCommand) { 620 BriefCommand = Command; 621 return; 622 } 623 PrevCommand = BriefCommand; 624 } else if (Info->IsHeaderfileCommand) { 625 if (!HeaderfileCommand) { 626 HeaderfileCommand = Command; 627 return; 628 } 629 PrevCommand = HeaderfileCommand; 630 } else { 631 // We don't want to check this command for duplicates. 632 return; 633 } 634 StringRef CommandName = Command->getCommandName(Traits); 635 StringRef PrevCommandName = PrevCommand->getCommandName(Traits); 636 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) 637 << Command->getCommandMarker() 638 << CommandName 639 << Command->getSourceRange(); 640 if (CommandName == PrevCommandName) 641 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) 642 << PrevCommand->getCommandMarker() 643 << PrevCommandName 644 << PrevCommand->getSourceRange(); 645 else 646 Diag(PrevCommand->getLocation(), 647 diag::note_doc_block_command_previous_alias) 648 << PrevCommand->getCommandMarker() 649 << PrevCommandName 650 << CommandName; 651 } 652 653 void Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { 654 if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand) 655 return; 656 657 const Decl *D = ThisDeclInfo->CommentDecl; 658 if (!D) 659 return; 660 661 if (D->hasAttr<DeprecatedAttr>() || 662 D->hasAttr<AvailabilityAttr>() || 663 D->hasAttr<UnavailableAttr>()) 664 return; 665 666 Diag(Command->getLocation(), 667 diag::warn_doc_deprecated_not_sync) 668 << Command->getSourceRange(); 669 670 // Try to emit a fixit with a deprecation attribute. 671 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 672 // Don't emit a Fix-It for non-member function definitions. GCC does not 673 // accept attributes on them. 674 const DeclContext *Ctx = FD->getDeclContext(); 675 if ((!Ctx || !Ctx->isRecord()) && 676 FD->doesThisDeclarationHaveABody()) 677 return; 678 679 StringRef AttributeSpelling = "__attribute__((deprecated))"; 680 if (PP) { 681 TokenValue Tokens[] = { 682 tok::kw___attribute, tok::l_paren, tok::l_paren, 683 PP->getIdentifierInfo("deprecated"), 684 tok::r_paren, tok::r_paren 685 }; 686 StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), 687 Tokens); 688 if (!MacroName.empty()) 689 AttributeSpelling = MacroName; 690 } 691 692 SmallString<64> TextToInsert(" "); 693 TextToInsert += AttributeSpelling; 694 Diag(FD->getLocEnd(), 695 diag::note_add_deprecation_attr) 696 << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1), 697 TextToInsert); 698 } 699 } 700 701 void Sema::resolveParamCommandIndexes(const FullComment *FC) { 702 if (!isFunctionDecl()) { 703 // We already warned that \\param commands are not attached to a function 704 // decl. 705 return; 706 } 707 708 SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands; 709 710 // Comment AST nodes that correspond to \c ParamVars for which we have 711 // found a \\param command or NULL if no documentation was found so far. 712 SmallVector<ParamCommandComment *, 8> ParamVarDocs; 713 714 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); 715 ParamVarDocs.resize(ParamVars.size(), NULL); 716 717 // First pass over all \\param commands: resolve all parameter names. 718 for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end(); 719 I != E; ++I) { 720 ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I); 721 if (!PCC || !PCC->hasParamName()) 722 continue; 723 StringRef ParamName = PCC->getParamNameAsWritten(); 724 725 // Check that referenced parameter name is in the function decl. 726 const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, 727 ParamVars); 728 if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { 729 PCC->setIsVarArgParam(); 730 continue; 731 } 732 if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { 733 UnresolvedParamCommands.push_back(PCC); 734 continue; 735 } 736 PCC->setParamIndex(ResolvedParamIndex); 737 if (ParamVarDocs[ResolvedParamIndex]) { 738 SourceRange ArgRange = PCC->getParamNameRange(); 739 Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate) 740 << ParamName << ArgRange; 741 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; 742 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) 743 << PrevCommand->getParamNameRange(); 744 } 745 ParamVarDocs[ResolvedParamIndex] = PCC; 746 } 747 748 // Find parameter declarations that have no corresponding \\param. 749 SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; 750 for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) { 751 if (!ParamVarDocs[i]) 752 OrphanedParamDecls.push_back(ParamVars[i]); 753 } 754 755 // Second pass over unresolved \\param commands: do typo correction. 756 // Suggest corrections from a set of parameter declarations that have no 757 // corresponding \\param. 758 for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) { 759 const ParamCommandComment *PCC = UnresolvedParamCommands[i]; 760 761 SourceRange ArgRange = PCC->getParamNameRange(); 762 StringRef ParamName = PCC->getParamNameAsWritten(); 763 Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) 764 << ParamName << ArgRange; 765 766 // All parameters documented -- can't suggest a correction. 767 if (OrphanedParamDecls.size() == 0) 768 continue; 769 770 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; 771 if (OrphanedParamDecls.size() == 1) { 772 // If one parameter is not documented then that parameter is the only 773 // possible suggestion. 774 CorrectedParamIndex = 0; 775 } else { 776 // Do typo correction. 777 CorrectedParamIndex = correctTypoInParmVarReference(ParamName, 778 OrphanedParamDecls); 779 } 780 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { 781 const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex]; 782 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) 783 Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) 784 << CorrectedII->getName() 785 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); 786 } 787 } 788 } 789 790 bool Sema::isFunctionDecl() { 791 if (!ThisDeclInfo) 792 return false; 793 if (!ThisDeclInfo->IsFilled) 794 inspectThisDecl(); 795 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind; 796 } 797 798 bool Sema::isAnyFunctionDecl() { 799 return isFunctionDecl() && ThisDeclInfo->CurrentDecl && 800 isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); 801 } 802 803 bool Sema::isFunctionOrMethodVariadic() { 804 if (!isAnyFunctionDecl() && !isObjCMethodDecl()) 805 return false; 806 if (const FunctionDecl *FD = 807 dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) 808 return FD->isVariadic(); 809 if (const ObjCMethodDecl *MD = 810 dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) 811 return MD->isVariadic(); 812 return false; 813 } 814 815 bool Sema::isObjCMethodDecl() { 816 return isFunctionDecl() && ThisDeclInfo->CurrentDecl && 817 isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl); 818 } 819 820 bool Sema::isFunctionPointerVarDecl() { 821 if (!ThisDeclInfo) 822 return false; 823 if (!ThisDeclInfo->IsFilled) 824 inspectThisDecl(); 825 if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) { 826 if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) { 827 QualType QT = VD->getType(); 828 return QT->isFunctionPointerType(); 829 } 830 } 831 return false; 832 } 833 834 bool Sema::isObjCPropertyDecl() { 835 if (!ThisDeclInfo) 836 return false; 837 if (!ThisDeclInfo->IsFilled) 838 inspectThisDecl(); 839 return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty; 840 } 841 842 bool Sema::isTemplateOrSpecialization() { 843 if (!ThisDeclInfo) 844 return false; 845 if (!ThisDeclInfo->IsFilled) 846 inspectThisDecl(); 847 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate; 848 } 849 850 bool Sema::isRecordLikeDecl() { 851 if (!ThisDeclInfo) 852 return false; 853 if (!ThisDeclInfo->IsFilled) 854 inspectThisDecl(); 855 return isUnionDecl() || isClassOrStructDecl() 856 || isObjCInterfaceDecl() || isObjCProtocolDecl(); 857 } 858 859 bool Sema::isUnionDecl() { 860 if (!ThisDeclInfo) 861 return false; 862 if (!ThisDeclInfo->IsFilled) 863 inspectThisDecl(); 864 if (const RecordDecl *RD = 865 dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl)) 866 return RD->isUnion(); 867 return false; 868 } 869 870 bool Sema::isClassOrStructDecl() { 871 if (!ThisDeclInfo) 872 return false; 873 if (!ThisDeclInfo->IsFilled) 874 inspectThisDecl(); 875 return ThisDeclInfo->CurrentDecl && 876 isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && 877 !isUnionDecl(); 878 } 879 880 bool Sema::isClassTemplateDecl() { 881 if (!ThisDeclInfo) 882 return false; 883 if (!ThisDeclInfo->IsFilled) 884 inspectThisDecl(); 885 return ThisDeclInfo->CurrentDecl && 886 (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl)); 887 } 888 889 bool Sema::isFunctionTemplateDecl() { 890 if (!ThisDeclInfo) 891 return false; 892 if (!ThisDeclInfo->IsFilled) 893 inspectThisDecl(); 894 return ThisDeclInfo->CurrentDecl && 895 (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)); 896 } 897 898 bool Sema::isObjCInterfaceDecl() { 899 if (!ThisDeclInfo) 900 return false; 901 if (!ThisDeclInfo->IsFilled) 902 inspectThisDecl(); 903 return ThisDeclInfo->CurrentDecl && 904 isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl); 905 } 906 907 bool Sema::isObjCProtocolDecl() { 908 if (!ThisDeclInfo) 909 return false; 910 if (!ThisDeclInfo->IsFilled) 911 inspectThisDecl(); 912 return ThisDeclInfo->CurrentDecl && 913 isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl); 914 } 915 916 ArrayRef<const ParmVarDecl *> Sema::getParamVars() { 917 if (!ThisDeclInfo->IsFilled) 918 inspectThisDecl(); 919 return ThisDeclInfo->ParamVars; 920 } 921 922 void Sema::inspectThisDecl() { 923 ThisDeclInfo->fill(); 924 } 925 926 unsigned Sema::resolveParmVarReference(StringRef Name, 927 ArrayRef<const ParmVarDecl *> ParamVars) { 928 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) { 929 const IdentifierInfo *II = ParamVars[i]->getIdentifier(); 930 if (II && II->getName() == Name) 931 return i; 932 } 933 if (Name == "..." && isFunctionOrMethodVariadic()) 934 return ParamCommandComment::VarArgParamIndex; 935 return ParamCommandComment::InvalidParamIndex; 936 } 937 938 namespace { 939 class SimpleTypoCorrector { 940 StringRef Typo; 941 const unsigned MaxEditDistance; 942 943 const NamedDecl *BestDecl; 944 unsigned BestEditDistance; 945 unsigned BestIndex; 946 unsigned NextIndex; 947 948 public: 949 SimpleTypoCorrector(StringRef Typo) : 950 Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3), 951 BestDecl(NULL), BestEditDistance(MaxEditDistance + 1), 952 BestIndex(0), NextIndex(0) 953 { } 954 955 void addDecl(const NamedDecl *ND); 956 957 const NamedDecl *getBestDecl() const { 958 if (BestEditDistance > MaxEditDistance) 959 return NULL; 960 961 return BestDecl; 962 } 963 964 unsigned getBestDeclIndex() const { 965 assert(getBestDecl()); 966 return BestIndex; 967 } 968 }; 969 970 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) { 971 unsigned CurrIndex = NextIndex++; 972 973 const IdentifierInfo *II = ND->getIdentifier(); 974 if (!II) 975 return; 976 977 StringRef Name = II->getName(); 978 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); 979 if (MinPossibleEditDistance > 0 && 980 Typo.size() / MinPossibleEditDistance < 3) 981 return; 982 983 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); 984 if (EditDistance < BestEditDistance) { 985 BestEditDistance = EditDistance; 986 BestDecl = ND; 987 BestIndex = CurrIndex; 988 } 989 } 990 } // unnamed namespace 991 992 unsigned Sema::correctTypoInParmVarReference( 993 StringRef Typo, 994 ArrayRef<const ParmVarDecl *> ParamVars) { 995 SimpleTypoCorrector Corrector(Typo); 996 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) 997 Corrector.addDecl(ParamVars[i]); 998 if (Corrector.getBestDecl()) 999 return Corrector.getBestDeclIndex(); 1000 else 1001 return ParamCommandComment::InvalidParamIndex; 1002 } 1003 1004 namespace { 1005 bool ResolveTParamReferenceHelper( 1006 StringRef Name, 1007 const TemplateParameterList *TemplateParameters, 1008 SmallVectorImpl<unsigned> *Position) { 1009 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { 1010 const NamedDecl *Param = TemplateParameters->getParam(i); 1011 const IdentifierInfo *II = Param->getIdentifier(); 1012 if (II && II->getName() == Name) { 1013 Position->push_back(i); 1014 return true; 1015 } 1016 1017 if (const TemplateTemplateParmDecl *TTP = 1018 dyn_cast<TemplateTemplateParmDecl>(Param)) { 1019 Position->push_back(i); 1020 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(), 1021 Position)) 1022 return true; 1023 Position->pop_back(); 1024 } 1025 } 1026 return false; 1027 } 1028 } // unnamed namespace 1029 1030 bool Sema::resolveTParamReference( 1031 StringRef Name, 1032 const TemplateParameterList *TemplateParameters, 1033 SmallVectorImpl<unsigned> *Position) { 1034 Position->clear(); 1035 if (!TemplateParameters) 1036 return false; 1037 1038 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position); 1039 } 1040 1041 namespace { 1042 void CorrectTypoInTParamReferenceHelper( 1043 const TemplateParameterList *TemplateParameters, 1044 SimpleTypoCorrector &Corrector) { 1045 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { 1046 const NamedDecl *Param = TemplateParameters->getParam(i); 1047 Corrector.addDecl(Param); 1048 1049 if (const TemplateTemplateParmDecl *TTP = 1050 dyn_cast<TemplateTemplateParmDecl>(Param)) 1051 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), 1052 Corrector); 1053 } 1054 } 1055 } // unnamed namespace 1056 1057 StringRef Sema::correctTypoInTParamReference( 1058 StringRef Typo, 1059 const TemplateParameterList *TemplateParameters) { 1060 SimpleTypoCorrector Corrector(Typo); 1061 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector); 1062 if (const NamedDecl *ND = Corrector.getBestDecl()) { 1063 const IdentifierInfo *II = ND->getIdentifier(); 1064 assert(II && "SimpleTypoCorrector should not return this decl"); 1065 return II->getName(); 1066 } 1067 return StringRef(); 1068 } 1069 1070 InlineCommandComment::RenderKind 1071 Sema::getInlineCommandRenderKind(StringRef Name) const { 1072 assert(Traits.getCommandInfo(Name)->IsInlineCommand); 1073 1074 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name) 1075 .Case("b", InlineCommandComment::RenderBold) 1076 .Cases("c", "p", InlineCommandComment::RenderMonospaced) 1077 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized) 1078 .Default(InlineCommandComment::RenderNormal); 1079 } 1080 1081 } // end namespace comments 1082 } // end namespace clang 1083 1084