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