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