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/CommentDiagnostic.h" 12 #include "clang/AST/CommentCommandTraits.h" 13 #include "clang/AST/Decl.h" 14 #include "clang/AST/DeclTemplate.h" 15 #include "clang/Basic/SourceManager.h" 16 #include "llvm/ADT/StringSwitch.h" 17 18 namespace clang { 19 namespace comments { 20 21 Sema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, 22 DiagnosticsEngine &Diags, const CommandTraits &Traits) : 23 Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), 24 ThisDeclInfo(NULL), BriefCommand(NULL), ReturnsCommand(NULL) { 25 } 26 27 void Sema::setDecl(const Decl *D) { 28 if (!D) 29 return; 30 31 ThisDeclInfo = new (Allocator) DeclInfo; 32 ThisDeclInfo->ThisDecl = D; 33 ThisDeclInfo->IsFilled = false; 34 } 35 36 ParagraphComment *Sema::actOnParagraphComment( 37 ArrayRef<InlineContentComment *> Content) { 38 return new (Allocator) ParagraphComment(Content); 39 } 40 41 BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin, 42 SourceLocation LocEnd, 43 StringRef Name) { 44 return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name); 45 } 46 47 void Sema::actOnBlockCommandArgs(BlockCommandComment *Command, 48 ArrayRef<BlockCommandComment::Argument> Args) { 49 Command->setArgs(Args); 50 } 51 52 void Sema::actOnBlockCommandFinish(BlockCommandComment *Command, 53 ParagraphComment *Paragraph) { 54 Command->setParagraph(Paragraph); 55 checkBlockCommandEmptyParagraph(Command); 56 checkBlockCommandDuplicate(Command); 57 checkReturnsCommand(Command); 58 } 59 60 ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin, 61 SourceLocation LocEnd, 62 StringRef Name) { 63 ParamCommandComment *Command = 64 new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name); 65 66 if (!isFunctionDecl()) 67 Diag(Command->getLocation(), 68 diag::warn_doc_param_not_attached_to_a_function_decl) 69 << Command->getCommandNameRange(); 70 71 return Command; 72 } 73 74 void Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, 75 SourceLocation ArgLocBegin, 76 SourceLocation ArgLocEnd, 77 StringRef Arg) { 78 ParamCommandComment::PassDirection Direction; 79 std::string ArgLower = Arg.lower(); 80 // TODO: optimize: lower Name first (need an API in SmallString for that), 81 // after that StringSwitch. 82 if (ArgLower == "[in]") 83 Direction = ParamCommandComment::In; 84 else if (ArgLower == "[out]") 85 Direction = ParamCommandComment::Out; 86 else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") 87 Direction = ParamCommandComment::InOut; 88 else { 89 // Remove spaces. 90 std::string::iterator O = ArgLower.begin(); 91 for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end(); 92 I != E; ++I) { 93 const char C = *I; 94 if (C != ' ' && C != '\n' && C != '\r' && 95 C != '\t' && C != '\v' && C != '\f') 96 *O++ = C; 97 } 98 ArgLower.resize(O - ArgLower.begin()); 99 100 bool RemovingWhitespaceHelped = false; 101 if (ArgLower == "[in]") { 102 Direction = ParamCommandComment::In; 103 RemovingWhitespaceHelped = true; 104 } else if (ArgLower == "[out]") { 105 Direction = ParamCommandComment::Out; 106 RemovingWhitespaceHelped = true; 107 } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") { 108 Direction = ParamCommandComment::InOut; 109 RemovingWhitespaceHelped = true; 110 } else { 111 Direction = ParamCommandComment::In; 112 RemovingWhitespaceHelped = false; 113 } 114 115 SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 116 if (RemovingWhitespaceHelped) 117 Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction) 118 << ArgRange 119 << FixItHint::CreateReplacement( 120 ArgRange, 121 ParamCommandComment::getDirectionAsString(Direction)); 122 else 123 Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) 124 << ArgRange; 125 } 126 Command->setDirection(Direction, /* Explicit = */ true); 127 } 128 129 void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, 130 SourceLocation ArgLocBegin, 131 SourceLocation ArgLocEnd, 132 StringRef Arg) { 133 // Parser will not feed us more arguments than needed. 134 assert(Command->getNumArgs() == 0); 135 136 if (!Command->isDirectionExplicit()) { 137 // User didn't provide a direction argument. 138 Command->setDirection(ParamCommandComment::In, /* Explicit = */ false); 139 } 140 typedef BlockCommandComment::Argument Argument; 141 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 142 ArgLocEnd), 143 Arg); 144 Command->setArgs(llvm::makeArrayRef(A, 1)); 145 146 if (!isFunctionDecl()) { 147 // We already warned that this \\param is not attached to a function decl. 148 return; 149 } 150 151 ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); 152 153 // Check that referenced parameter name is in the function decl. 154 const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars); 155 if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) { 156 Command->setParamIndex(ResolvedParamIndex); 157 if (ParamVarDocs[ResolvedParamIndex]) { 158 SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 159 Diag(ArgLocBegin, diag::warn_doc_param_duplicate) 160 << Arg << ArgRange; 161 ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; 162 Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) 163 << PrevCommand->getParamNameRange(); 164 } 165 ParamVarDocs[ResolvedParamIndex] = Command; 166 return; 167 } 168 169 SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 170 Diag(ArgLocBegin, diag::warn_doc_param_not_found) 171 << Arg << ArgRange; 172 173 // No parameters -- can't suggest a correction. 174 if (ParamVars.size() == 0) 175 return; 176 177 unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; 178 if (ParamVars.size() == 1) { 179 // If function has only one parameter then only that parameter 180 // can be documented. 181 CorrectedParamIndex = 0; 182 } else { 183 // Do typo correction. 184 CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars); 185 } 186 if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { 187 const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex]; 188 if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) 189 Diag(ArgLocBegin, diag::note_doc_param_name_suggestion) 190 << CorrectedII->getName() 191 << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); 192 } 193 194 return; 195 } 196 197 void Sema::actOnParamCommandFinish(ParamCommandComment *Command, 198 ParagraphComment *Paragraph) { 199 Command->setParagraph(Paragraph); 200 checkBlockCommandEmptyParagraph(Command); 201 } 202 203 TParamCommandComment *Sema::actOnTParamCommandStart(SourceLocation LocBegin, 204 SourceLocation LocEnd, 205 StringRef Name) { 206 TParamCommandComment *Command = 207 new (Allocator) TParamCommandComment(LocBegin, LocEnd, Name); 208 209 if (!isTemplateOrSpecialization()) 210 Diag(Command->getLocation(), 211 diag::warn_doc_tparam_not_attached_to_a_template_decl) 212 << Command->getCommandNameRange(); 213 214 return Command; 215 } 216 217 void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command, 218 SourceLocation ArgLocBegin, 219 SourceLocation ArgLocEnd, 220 StringRef Arg) { 221 // Parser will not feed us more arguments than needed. 222 assert(Command->getNumArgs() == 0); 223 224 typedef BlockCommandComment::Argument Argument; 225 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 226 ArgLocEnd), 227 Arg); 228 Command->setArgs(llvm::makeArrayRef(A, 1)); 229 230 if (!isTemplateOrSpecialization()) { 231 // We already warned that this \\tparam is not attached to a template decl. 232 return; 233 } 234 235 const TemplateParameterList *TemplateParameters = 236 ThisDeclInfo->TemplateParameters; 237 SmallVector<unsigned, 2> Position; 238 if (resolveTParamReference(Arg, TemplateParameters, &Position)) { 239 Command->setPosition(copyArray(llvm::makeArrayRef(Position))); 240 llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt = 241 TemplateParameterDocs.find(Arg); 242 if (PrevCommandIt != TemplateParameterDocs.end()) { 243 SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 244 Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate) 245 << Arg << ArgRange; 246 TParamCommandComment *PrevCommand = PrevCommandIt->second; 247 Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous) 248 << PrevCommand->getParamNameRange(); 249 } 250 TemplateParameterDocs[Arg] = Command; 251 return; 252 } 253 254 SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 255 Diag(ArgLocBegin, diag::warn_doc_tparam_not_found) 256 << Arg << ArgRange; 257 258 if (!TemplateParameters || TemplateParameters->size() == 0) 259 return; 260 261 StringRef CorrectedName; 262 if (TemplateParameters->size() == 1) { 263 const NamedDecl *Param = TemplateParameters->getParam(0); 264 const IdentifierInfo *II = Param->getIdentifier(); 265 if (II) 266 CorrectedName = II->getName(); 267 } else { 268 CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters); 269 } 270 271 if (!CorrectedName.empty()) { 272 Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion) 273 << CorrectedName 274 << FixItHint::CreateReplacement(ArgRange, CorrectedName); 275 } 276 277 return; 278 } 279 280 void Sema::actOnTParamCommandFinish(TParamCommandComment *Command, 281 ParagraphComment *Paragraph) { 282 Command->setParagraph(Paragraph); 283 checkBlockCommandEmptyParagraph(Command); 284 } 285 286 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, 287 SourceLocation CommandLocEnd, 288 StringRef CommandName) { 289 ArrayRef<InlineCommandComment::Argument> Args; 290 return new (Allocator) InlineCommandComment( 291 CommandLocBegin, 292 CommandLocEnd, 293 CommandName, 294 getInlineCommandRenderKind(CommandName), 295 Args); 296 } 297 298 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, 299 SourceLocation CommandLocEnd, 300 StringRef CommandName, 301 SourceLocation ArgLocBegin, 302 SourceLocation ArgLocEnd, 303 StringRef Arg) { 304 typedef InlineCommandComment::Argument Argument; 305 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 306 ArgLocEnd), 307 Arg); 308 309 return new (Allocator) InlineCommandComment( 310 CommandLocBegin, 311 CommandLocEnd, 312 CommandName, 313 getInlineCommandRenderKind(CommandName), 314 llvm::makeArrayRef(A, 1)); 315 } 316 317 InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, 318 SourceLocation LocEnd, 319 StringRef Name) { 320 ArrayRef<InlineCommandComment::Argument> Args; 321 return new (Allocator) InlineCommandComment( 322 LocBegin, LocEnd, Name, 323 InlineCommandComment::RenderNormal, 324 Args); 325 } 326 327 TextComment *Sema::actOnText(SourceLocation LocBegin, 328 SourceLocation LocEnd, 329 StringRef Text) { 330 return new (Allocator) TextComment(LocBegin, LocEnd, Text); 331 } 332 333 VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc, 334 StringRef Name) { 335 return new (Allocator) VerbatimBlockComment( 336 Loc, 337 Loc.getLocWithOffset(1 + Name.size()), 338 Name); 339 } 340 341 VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc, 342 StringRef Text) { 343 return new (Allocator) VerbatimBlockLineComment(Loc, Text); 344 } 345 346 void Sema::actOnVerbatimBlockFinish( 347 VerbatimBlockComment *Block, 348 SourceLocation CloseNameLocBegin, 349 StringRef CloseName, 350 ArrayRef<VerbatimBlockLineComment *> Lines) { 351 Block->setCloseName(CloseName, CloseNameLocBegin); 352 Block->setLines(Lines); 353 } 354 355 VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, 356 StringRef Name, 357 SourceLocation TextBegin, 358 StringRef Text) { 359 return new (Allocator) VerbatimLineComment( 360 LocBegin, 361 TextBegin.getLocWithOffset(Text.size()), 362 Name, 363 TextBegin, 364 Text); 365 } 366 367 HTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin, 368 StringRef TagName) { 369 return new (Allocator) HTMLStartTagComment(LocBegin, TagName); 370 } 371 372 void Sema::actOnHTMLStartTagFinish( 373 HTMLStartTagComment *Tag, 374 ArrayRef<HTMLStartTagComment::Attribute> Attrs, 375 SourceLocation GreaterLoc, 376 bool IsSelfClosing) { 377 Tag->setAttrs(Attrs); 378 Tag->setGreaterLoc(GreaterLoc); 379 if (IsSelfClosing) 380 Tag->setSelfClosing(); 381 else if (!isHTMLEndTagForbidden(Tag->getTagName())) 382 HTMLOpenTags.push_back(Tag); 383 } 384 385 HTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, 386 SourceLocation LocEnd, 387 StringRef TagName) { 388 HTMLEndTagComment *HET = 389 new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName); 390 if (isHTMLEndTagForbidden(TagName)) { 391 Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden) 392 << TagName << HET->getSourceRange(); 393 return HET; 394 } 395 396 bool FoundOpen = false; 397 for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator 398 I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend(); 399 I != E; ++I) { 400 if ((*I)->getTagName() == TagName) { 401 FoundOpen = true; 402 break; 403 } 404 } 405 if (!FoundOpen) { 406 Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced) 407 << HET->getSourceRange(); 408 return HET; 409 } 410 411 while (!HTMLOpenTags.empty()) { 412 const HTMLStartTagComment *HST = HTMLOpenTags.back(); 413 HTMLOpenTags.pop_back(); 414 StringRef LastNotClosedTagName = HST->getTagName(); 415 if (LastNotClosedTagName == TagName) 416 break; 417 418 if (isHTMLEndTagOptional(LastNotClosedTagName)) 419 continue; 420 421 bool OpenLineInvalid; 422 const unsigned OpenLine = SourceMgr.getPresumedLineNumber( 423 HST->getLocation(), 424 &OpenLineInvalid); 425 bool CloseLineInvalid; 426 const unsigned CloseLine = SourceMgr.getPresumedLineNumber( 427 HET->getLocation(), 428 &CloseLineInvalid); 429 430 if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) 431 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) 432 << HST->getTagName() << HET->getTagName() 433 << HST->getSourceRange() << HET->getSourceRange(); 434 else { 435 Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) 436 << HST->getTagName() << HET->getTagName() 437 << HST->getSourceRange(); 438 Diag(HET->getLocation(), diag::note_doc_html_end_tag) 439 << HET->getSourceRange(); 440 } 441 } 442 443 return HET; 444 } 445 446 FullComment *Sema::actOnFullComment( 447 ArrayRef<BlockContentComment *> Blocks) { 448 return new (Allocator) FullComment(Blocks, ThisDeclInfo); 449 } 450 451 void Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { 452 ParagraphComment *Paragraph = Command->getParagraph(); 453 if (Paragraph->isWhitespace()) { 454 SourceLocation DiagLoc; 455 if (Command->getNumArgs() > 0) 456 DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd(); 457 if (!DiagLoc.isValid()) 458 DiagLoc = Command->getCommandNameRange().getEnd(); 459 Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) 460 << Command->getCommandName() 461 << Command->getSourceRange(); 462 } 463 } 464 465 void Sema::checkReturnsCommand(const BlockCommandComment *Command) { 466 if (!Traits.isReturnsCommand(Command->getCommandName())) 467 return; 468 if (isFunctionDecl()) { 469 if (ThisDeclInfo->ResultType->isVoidType()) { 470 unsigned DiagKind; 471 switch (ThisDeclInfo->ThisDecl->getKind()) { 472 default: 473 if (ThisDeclInfo->IsObjCMethod) 474 DiagKind = 3; 475 else 476 DiagKind = 0; 477 break; 478 case Decl::CXXConstructor: 479 DiagKind = 1; 480 break; 481 case Decl::CXXDestructor: 482 DiagKind = 2; 483 break; 484 } 485 Diag(Command->getLocation(), 486 diag::warn_doc_returns_attached_to_a_void_function) 487 << Command->getCommandName() 488 << DiagKind 489 << Command->getSourceRange(); 490 } 491 return; 492 } 493 Diag(Command->getLocation(), 494 diag::warn_doc_returns_not_attached_to_a_function_decl) 495 << Command->getCommandName() 496 << Command->getSourceRange(); 497 } 498 499 void Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { 500 StringRef Name = Command->getCommandName(); 501 const BlockCommandComment *PrevCommand = NULL; 502 if (Traits.isBriefCommand(Name)) { 503 if (!BriefCommand) { 504 BriefCommand = Command; 505 return; 506 } 507 PrevCommand = BriefCommand; 508 } else if (Traits.isReturnsCommand(Name)) { 509 if (!ReturnsCommand) { 510 ReturnsCommand = Command; 511 return; 512 } 513 PrevCommand = ReturnsCommand; 514 } else { 515 // We don't want to check this command for duplicates. 516 return; 517 } 518 Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) 519 << Name 520 << Command->getSourceRange(); 521 if (Name == PrevCommand->getCommandName()) 522 Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) 523 << PrevCommand->getCommandName() 524 << Command->getSourceRange(); 525 else 526 Diag(PrevCommand->getLocation(), 527 diag::note_doc_block_command_previous_alias) 528 << PrevCommand->getCommandName() 529 << Name; 530 } 531 532 bool Sema::isFunctionDecl() { 533 if (!ThisDeclInfo) 534 return false; 535 if (!ThisDeclInfo->IsFilled) 536 inspectThisDecl(); 537 return ThisDeclInfo->getKind() == DeclInfo::FunctionKind; 538 } 539 540 bool Sema::isTemplateOrSpecialization() { 541 if (!ThisDeclInfo) 542 return false; 543 if (!ThisDeclInfo->IsFilled) 544 inspectThisDecl(); 545 return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate; 546 } 547 548 ArrayRef<const ParmVarDecl *> Sema::getParamVars() { 549 if (!ThisDeclInfo->IsFilled) 550 inspectThisDecl(); 551 return ThisDeclInfo->ParamVars; 552 } 553 554 void Sema::inspectThisDecl() { 555 ThisDeclInfo->fill(); 556 ParamVarDocs.resize(ThisDeclInfo->ParamVars.size(), NULL); 557 } 558 559 unsigned Sema::resolveParmVarReference(StringRef Name, 560 ArrayRef<const ParmVarDecl *> ParamVars) { 561 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) { 562 const IdentifierInfo *II = ParamVars[i]->getIdentifier(); 563 if (II && II->getName() == Name) 564 return i; 565 } 566 return ParamCommandComment::InvalidParamIndex; 567 } 568 569 namespace { 570 class SimpleTypoCorrector { 571 StringRef Typo; 572 const unsigned MaxEditDistance; 573 574 const NamedDecl *BestDecl; 575 unsigned BestEditDistance; 576 unsigned BestIndex; 577 unsigned NextIndex; 578 579 public: 580 SimpleTypoCorrector(StringRef Typo) : 581 Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3), 582 BestDecl(NULL), BestEditDistance(MaxEditDistance + 1), 583 BestIndex(0), NextIndex(0) 584 { } 585 586 void addDecl(const NamedDecl *ND); 587 588 const NamedDecl *getBestDecl() const { 589 if (BestEditDistance > MaxEditDistance) 590 return NULL; 591 592 return BestDecl; 593 } 594 595 unsigned getBestDeclIndex() const { 596 assert(getBestDecl()); 597 return BestIndex; 598 } 599 }; 600 601 void SimpleTypoCorrector::addDecl(const NamedDecl *ND) { 602 unsigned CurrIndex = NextIndex++; 603 604 const IdentifierInfo *II = ND->getIdentifier(); 605 if (!II) 606 return; 607 608 StringRef Name = II->getName(); 609 unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); 610 if (MinPossibleEditDistance > 0 && 611 Typo.size() / MinPossibleEditDistance < 3) 612 return; 613 614 unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); 615 if (EditDistance < BestEditDistance) { 616 BestEditDistance = EditDistance; 617 BestDecl = ND; 618 BestIndex = CurrIndex; 619 } 620 } 621 } // unnamed namespace 622 623 unsigned Sema::correctTypoInParmVarReference( 624 StringRef Typo, 625 ArrayRef<const ParmVarDecl *> ParamVars) { 626 SimpleTypoCorrector Corrector(Typo); 627 for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) 628 Corrector.addDecl(ParamVars[i]); 629 if (Corrector.getBestDecl()) 630 return Corrector.getBestDeclIndex(); 631 else 632 return ParamCommandComment::InvalidParamIndex;; 633 } 634 635 namespace { 636 bool ResolveTParamReferenceHelper( 637 StringRef Name, 638 const TemplateParameterList *TemplateParameters, 639 SmallVectorImpl<unsigned> *Position) { 640 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { 641 const NamedDecl *Param = TemplateParameters->getParam(i); 642 const IdentifierInfo *II = Param->getIdentifier(); 643 if (II && II->getName() == Name) { 644 Position->push_back(i); 645 return true; 646 } 647 648 if (const TemplateTemplateParmDecl *TTP = 649 dyn_cast<TemplateTemplateParmDecl>(Param)) { 650 Position->push_back(i); 651 if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(), 652 Position)) 653 return true; 654 Position->pop_back(); 655 } 656 } 657 return false; 658 } 659 } // unnamed namespace 660 661 bool Sema::resolveTParamReference( 662 StringRef Name, 663 const TemplateParameterList *TemplateParameters, 664 SmallVectorImpl<unsigned> *Position) { 665 Position->clear(); 666 if (!TemplateParameters) 667 return false; 668 669 return ResolveTParamReferenceHelper(Name, TemplateParameters, Position); 670 } 671 672 namespace { 673 void CorrectTypoInTParamReferenceHelper( 674 const TemplateParameterList *TemplateParameters, 675 SimpleTypoCorrector &Corrector) { 676 for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { 677 const NamedDecl *Param = TemplateParameters->getParam(i); 678 Corrector.addDecl(Param); 679 680 if (const TemplateTemplateParmDecl *TTP = 681 dyn_cast<TemplateTemplateParmDecl>(Param)) 682 CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), 683 Corrector); 684 } 685 } 686 } // unnamed namespace 687 688 StringRef Sema::correctTypoInTParamReference( 689 StringRef Typo, 690 const TemplateParameterList *TemplateParameters) { 691 SimpleTypoCorrector Corrector(Typo); 692 CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector); 693 if (const NamedDecl *ND = Corrector.getBestDecl()) { 694 const IdentifierInfo *II = ND->getIdentifier(); 695 assert(II && "SimpleTypoCorrector should not return this decl"); 696 return II->getName(); 697 } 698 return StringRef(); 699 } 700 701 InlineCommandComment::RenderKind 702 Sema::getInlineCommandRenderKind(StringRef Name) const { 703 assert(Traits.isInlineCommand(Name)); 704 705 return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name) 706 .Case("b", InlineCommandComment::RenderBold) 707 .Cases("c", "p", InlineCommandComment::RenderMonospaced) 708 .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized) 709 .Default(InlineCommandComment::RenderNormal); 710 } 711 712 bool Sema::isHTMLEndTagOptional(StringRef Name) { 713 return llvm::StringSwitch<bool>(Name) 714 .Case("p", true) 715 .Case("li", true) 716 .Case("dt", true) 717 .Case("dd", true) 718 .Case("tr", true) 719 .Case("th", true) 720 .Case("td", true) 721 .Case("thead", true) 722 .Case("tfoot", true) 723 .Case("tbody", true) 724 .Case("colgroup", true) 725 .Default(false); 726 } 727 728 bool Sema::isHTMLEndTagForbidden(StringRef Name) { 729 return llvm::StringSwitch<bool>(Name) 730 .Case("br", true) 731 .Case("hr", true) 732 .Case("img", true) 733 .Case("col", true) 734 .Default(false); 735 } 736 737 } // end namespace comments 738 } // end namespace clang 739 740