1239313Sdim//===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===// 2239313Sdim// 3239313Sdim// The LLVM Compiler Infrastructure 4239313Sdim// 5239313Sdim// This file is distributed under the University of Illinois Open Source 6239313Sdim// License. See LICENSE.TXT for details. 7239313Sdim// 8239313Sdim//===----------------------------------------------------------------------===// 9239313Sdim 10239313Sdim#include "clang/AST/CommentSema.h" 11249423Sdim#include "clang/AST/Attr.h" 12249423Sdim#include "clang/AST/CommentCommandTraits.h" 13239313Sdim#include "clang/AST/CommentDiagnostic.h" 14239313Sdim#include "clang/AST/Decl.h" 15239313Sdim#include "clang/AST/DeclTemplate.h" 16239313Sdim#include "clang/Basic/SourceManager.h" 17243830Sdim#include "clang/Lex/Preprocessor.h" 18249423Sdim#include "llvm/ADT/SmallString.h" 19239313Sdim#include "llvm/ADT/StringSwitch.h" 20239313Sdim 21239313Sdimnamespace clang { 22239313Sdimnamespace comments { 23239313Sdim 24243830Sdimnamespace { 25243830Sdim#include "clang/AST/CommentHTMLTagsProperties.inc" 26243830Sdim} // unnamed namespace 27243830Sdim 28239313SdimSema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, 29243830Sdim DiagnosticsEngine &Diags, CommandTraits &Traits, 30243830Sdim const Preprocessor *PP) : 31239313Sdim Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), 32263508Sdim PP(PP), ThisDeclInfo(NULL), BriefCommand(NULL), HeaderfileCommand(NULL) { 33239313Sdim} 34239313Sdim 35239313Sdimvoid Sema::setDecl(const Decl *D) { 36239313Sdim if (!D) 37239313Sdim return; 38239313Sdim 39239313Sdim ThisDeclInfo = new (Allocator) DeclInfo; 40243830Sdim ThisDeclInfo->CommentDecl = D; 41239313Sdim ThisDeclInfo->IsFilled = false; 42239313Sdim} 43239313Sdim 44239313SdimParagraphComment *Sema::actOnParagraphComment( 45239313Sdim ArrayRef<InlineContentComment *> Content) { 46239313Sdim return new (Allocator) ParagraphComment(Content); 47239313Sdim} 48239313Sdim 49249423SdimBlockCommandComment *Sema::actOnBlockCommandStart( 50249423Sdim SourceLocation LocBegin, 51249423Sdim SourceLocation LocEnd, 52249423Sdim unsigned CommandID, 53249423Sdim CommandMarkerKind CommandMarker) { 54249423Sdim BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd, 55249423Sdim CommandID, 56249423Sdim CommandMarker); 57249423Sdim checkContainerDecl(BC); 58249423Sdim return BC; 59239313Sdim} 60239313Sdim 61239313Sdimvoid Sema::actOnBlockCommandArgs(BlockCommandComment *Command, 62239313Sdim ArrayRef<BlockCommandComment::Argument> Args) { 63239313Sdim Command->setArgs(Args); 64239313Sdim} 65239313Sdim 66239313Sdimvoid Sema::actOnBlockCommandFinish(BlockCommandComment *Command, 67239313Sdim ParagraphComment *Paragraph) { 68239313Sdim Command->setParagraph(Paragraph); 69239313Sdim checkBlockCommandEmptyParagraph(Command); 70239313Sdim checkBlockCommandDuplicate(Command); 71239313Sdim checkReturnsCommand(Command); 72243830Sdim checkDeprecatedCommand(Command); 73239313Sdim} 74239313Sdim 75249423SdimParamCommandComment *Sema::actOnParamCommandStart( 76249423Sdim SourceLocation LocBegin, 77249423Sdim SourceLocation LocEnd, 78249423Sdim unsigned CommandID, 79249423Sdim CommandMarkerKind CommandMarker) { 80239313Sdim ParamCommandComment *Command = 81249423Sdim new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID, 82249423Sdim CommandMarker); 83239313Sdim 84239313Sdim if (!isFunctionDecl()) 85239313Sdim Diag(Command->getLocation(), 86239313Sdim diag::warn_doc_param_not_attached_to_a_function_decl) 87249423Sdim << CommandMarker 88243830Sdim << Command->getCommandNameRange(Traits); 89239313Sdim 90239313Sdim return Command; 91239313Sdim} 92239313Sdim 93249423Sdimvoid Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { 94249423Sdim const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); 95249423Sdim if (!Info->IsFunctionDeclarationCommand) 96249423Sdim return; 97249423Sdim 98249423Sdim unsigned DiagSelect; 99249423Sdim switch (Comment->getCommandID()) { 100249423Sdim case CommandTraits::KCI_function: 101263508Sdim DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0; 102249423Sdim break; 103249423Sdim case CommandTraits::KCI_functiongroup: 104263508Sdim DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0; 105249423Sdim break; 106249423Sdim case CommandTraits::KCI_method: 107249423Sdim DiagSelect = !isObjCMethodDecl() ? 3 : 0; 108249423Sdim break; 109249423Sdim case CommandTraits::KCI_methodgroup: 110249423Sdim DiagSelect = !isObjCMethodDecl() ? 4 : 0; 111249423Sdim break; 112249423Sdim case CommandTraits::KCI_callback: 113249423Sdim DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0; 114249423Sdim break; 115249423Sdim default: 116249423Sdim DiagSelect = 0; 117249423Sdim break; 118249423Sdim } 119249423Sdim if (DiagSelect) 120249423Sdim Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch) 121249423Sdim << Comment->getCommandMarker() 122249423Sdim << (DiagSelect-1) << (DiagSelect-1) 123249423Sdim << Comment->getSourceRange(); 124249423Sdim} 125249423Sdim 126249423Sdimvoid Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { 127249423Sdim const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); 128249423Sdim if (!Info->IsRecordLikeDeclarationCommand) 129249423Sdim return; 130249423Sdim unsigned DiagSelect; 131249423Sdim switch (Comment->getCommandID()) { 132249423Sdim case CommandTraits::KCI_class: 133263508Sdim DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0; 134263508Sdim // Allow @class command on @interface declarations. 135263508Sdim // FIXME. Currently, \class and @class are indistinguishable. So, 136263508Sdim // \class is also allowed on an @interface declaration 137263508Sdim if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl()) 138263508Sdim DiagSelect = 0; 139249423Sdim break; 140249423Sdim case CommandTraits::KCI_interface: 141249423Sdim DiagSelect = !isObjCInterfaceDecl() ? 2 : 0; 142249423Sdim break; 143249423Sdim case CommandTraits::KCI_protocol: 144249423Sdim DiagSelect = !isObjCProtocolDecl() ? 3 : 0; 145249423Sdim break; 146249423Sdim case CommandTraits::KCI_struct: 147249423Sdim DiagSelect = !isClassOrStructDecl() ? 4 : 0; 148249423Sdim break; 149249423Sdim case CommandTraits::KCI_union: 150249423Sdim DiagSelect = !isUnionDecl() ? 5 : 0; 151249423Sdim break; 152249423Sdim default: 153249423Sdim DiagSelect = 0; 154249423Sdim break; 155249423Sdim } 156249423Sdim if (DiagSelect) 157249423Sdim Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch) 158249423Sdim << Comment->getCommandMarker() 159249423Sdim << (DiagSelect-1) << (DiagSelect-1) 160249423Sdim << Comment->getSourceRange(); 161249423Sdim} 162249423Sdim 163249423Sdimvoid Sema::checkContainerDecl(const BlockCommandComment *Comment) { 164249423Sdim const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); 165249423Sdim if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl()) 166249423Sdim return; 167249423Sdim unsigned DiagSelect; 168249423Sdim switch (Comment->getCommandID()) { 169249423Sdim case CommandTraits::KCI_classdesign: 170249423Sdim DiagSelect = 1; 171249423Sdim break; 172249423Sdim case CommandTraits::KCI_coclass: 173249423Sdim DiagSelect = 2; 174249423Sdim break; 175249423Sdim case CommandTraits::KCI_dependency: 176249423Sdim DiagSelect = 3; 177249423Sdim break; 178249423Sdim case CommandTraits::KCI_helper: 179249423Sdim DiagSelect = 4; 180249423Sdim break; 181249423Sdim case CommandTraits::KCI_helperclass: 182249423Sdim DiagSelect = 5; 183249423Sdim break; 184249423Sdim case CommandTraits::KCI_helps: 185249423Sdim DiagSelect = 6; 186249423Sdim break; 187249423Sdim case CommandTraits::KCI_instancesize: 188249423Sdim DiagSelect = 7; 189249423Sdim break; 190249423Sdim case CommandTraits::KCI_ownership: 191249423Sdim DiagSelect = 8; 192249423Sdim break; 193249423Sdim case CommandTraits::KCI_performance: 194249423Sdim DiagSelect = 9; 195249423Sdim break; 196249423Sdim case CommandTraits::KCI_security: 197249423Sdim DiagSelect = 10; 198249423Sdim break; 199249423Sdim case CommandTraits::KCI_superclass: 200249423Sdim DiagSelect = 11; 201249423Sdim break; 202249423Sdim default: 203249423Sdim DiagSelect = 0; 204249423Sdim break; 205249423Sdim } 206249423Sdim if (DiagSelect) 207249423Sdim Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch) 208249423Sdim << Comment->getCommandMarker() 209249423Sdim << (DiagSelect-1) 210249423Sdim << Comment->getSourceRange(); 211249423Sdim} 212249423Sdim 213263508Sdim/// \brief Turn a string into the corresponding PassDirection or -1 if it's not 214263508Sdim/// valid. 215263508Sdimstatic int getParamPassDirection(StringRef Arg) { 216263508Sdim return llvm::StringSwitch<int>(Arg) 217263508Sdim .Case("[in]", ParamCommandComment::In) 218263508Sdim .Case("[out]", ParamCommandComment::Out) 219263508Sdim .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut) 220263508Sdim .Default(-1); 221263508Sdim} 222263508Sdim 223239313Sdimvoid Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, 224239313Sdim SourceLocation ArgLocBegin, 225239313Sdim SourceLocation ArgLocEnd, 226239313Sdim StringRef Arg) { 227239313Sdim std::string ArgLower = Arg.lower(); 228263508Sdim int Direction = getParamPassDirection(ArgLower); 229239313Sdim 230263508Sdim if (Direction == -1) { 231263508Sdim // Try again with whitespace removed. 232263508Sdim ArgLower.erase( 233263508Sdim std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace), 234263508Sdim ArgLower.end()); 235263508Sdim Direction = getParamPassDirection(ArgLower); 236239313Sdim 237239313Sdim SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 238263508Sdim if (Direction != -1) { 239263508Sdim const char *FixedName = ParamCommandComment::getDirectionAsString( 240263508Sdim (ParamCommandComment::PassDirection)Direction); 241239313Sdim Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction) 242263508Sdim << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName); 243263508Sdim } else { 244263508Sdim Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange; 245263508Sdim Direction = ParamCommandComment::In; // Sane fall back. 246263508Sdim } 247239313Sdim } 248263508Sdim Command->setDirection((ParamCommandComment::PassDirection)Direction, 249263508Sdim /*Explicit=*/true); 250239313Sdim} 251239313Sdim 252239313Sdimvoid Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command, 253239313Sdim SourceLocation ArgLocBegin, 254239313Sdim SourceLocation ArgLocEnd, 255239313Sdim StringRef Arg) { 256239313Sdim // Parser will not feed us more arguments than needed. 257239313Sdim assert(Command->getNumArgs() == 0); 258239313Sdim 259239313Sdim if (!Command->isDirectionExplicit()) { 260239313Sdim // User didn't provide a direction argument. 261239313Sdim Command->setDirection(ParamCommandComment::In, /* Explicit = */ false); 262239313Sdim } 263239313Sdim typedef BlockCommandComment::Argument Argument; 264239313Sdim Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 265239313Sdim ArgLocEnd), 266239313Sdim Arg); 267239313Sdim Command->setArgs(llvm::makeArrayRef(A, 1)); 268239313Sdim} 269239313Sdim 270239313Sdimvoid Sema::actOnParamCommandFinish(ParamCommandComment *Command, 271239313Sdim ParagraphComment *Paragraph) { 272239313Sdim Command->setParagraph(Paragraph); 273239313Sdim checkBlockCommandEmptyParagraph(Command); 274239313Sdim} 275239313Sdim 276249423SdimTParamCommandComment *Sema::actOnTParamCommandStart( 277249423Sdim SourceLocation LocBegin, 278249423Sdim SourceLocation LocEnd, 279249423Sdim unsigned CommandID, 280249423Sdim CommandMarkerKind CommandMarker) { 281239313Sdim TParamCommandComment *Command = 282249423Sdim new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID, 283249423Sdim CommandMarker); 284239313Sdim 285239313Sdim if (!isTemplateOrSpecialization()) 286239313Sdim Diag(Command->getLocation(), 287239313Sdim diag::warn_doc_tparam_not_attached_to_a_template_decl) 288249423Sdim << CommandMarker 289243830Sdim << Command->getCommandNameRange(Traits); 290239313Sdim 291239313Sdim return Command; 292239313Sdim} 293239313Sdim 294239313Sdimvoid Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command, 295239313Sdim SourceLocation ArgLocBegin, 296239313Sdim SourceLocation ArgLocEnd, 297239313Sdim StringRef Arg) { 298239313Sdim // Parser will not feed us more arguments than needed. 299239313Sdim assert(Command->getNumArgs() == 0); 300239313Sdim 301239313Sdim typedef BlockCommandComment::Argument Argument; 302239313Sdim Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 303239313Sdim ArgLocEnd), 304239313Sdim Arg); 305239313Sdim Command->setArgs(llvm::makeArrayRef(A, 1)); 306239313Sdim 307239313Sdim if (!isTemplateOrSpecialization()) { 308239313Sdim // We already warned that this \\tparam is not attached to a template decl. 309239313Sdim return; 310239313Sdim } 311239313Sdim 312239313Sdim const TemplateParameterList *TemplateParameters = 313239313Sdim ThisDeclInfo->TemplateParameters; 314239313Sdim SmallVector<unsigned, 2> Position; 315239313Sdim if (resolveTParamReference(Arg, TemplateParameters, &Position)) { 316239313Sdim Command->setPosition(copyArray(llvm::makeArrayRef(Position))); 317263508Sdim TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg]; 318263508Sdim if (PrevCommand) { 319239313Sdim SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 320239313Sdim Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate) 321239313Sdim << Arg << ArgRange; 322239313Sdim Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous) 323239313Sdim << PrevCommand->getParamNameRange(); 324239313Sdim } 325263508Sdim PrevCommand = Command; 326239313Sdim return; 327239313Sdim } 328239313Sdim 329239313Sdim SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 330239313Sdim Diag(ArgLocBegin, diag::warn_doc_tparam_not_found) 331239313Sdim << Arg << ArgRange; 332239313Sdim 333239313Sdim if (!TemplateParameters || TemplateParameters->size() == 0) 334239313Sdim return; 335239313Sdim 336239313Sdim StringRef CorrectedName; 337239313Sdim if (TemplateParameters->size() == 1) { 338239313Sdim const NamedDecl *Param = TemplateParameters->getParam(0); 339239313Sdim const IdentifierInfo *II = Param->getIdentifier(); 340239313Sdim if (II) 341239313Sdim CorrectedName = II->getName(); 342239313Sdim } else { 343239313Sdim CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters); 344239313Sdim } 345239313Sdim 346239313Sdim if (!CorrectedName.empty()) { 347239313Sdim Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion) 348239313Sdim << CorrectedName 349239313Sdim << FixItHint::CreateReplacement(ArgRange, CorrectedName); 350239313Sdim } 351239313Sdim 352239313Sdim return; 353239313Sdim} 354239313Sdim 355239313Sdimvoid Sema::actOnTParamCommandFinish(TParamCommandComment *Command, 356239313Sdim ParagraphComment *Paragraph) { 357239313Sdim Command->setParagraph(Paragraph); 358239313Sdim checkBlockCommandEmptyParagraph(Command); 359239313Sdim} 360239313Sdim 361239313SdimInlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, 362239313Sdim SourceLocation CommandLocEnd, 363243830Sdim unsigned CommandID) { 364239313Sdim ArrayRef<InlineCommandComment::Argument> Args; 365243830Sdim StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; 366239313Sdim return new (Allocator) InlineCommandComment( 367239313Sdim CommandLocBegin, 368239313Sdim CommandLocEnd, 369243830Sdim CommandID, 370239313Sdim getInlineCommandRenderKind(CommandName), 371239313Sdim Args); 372239313Sdim} 373239313Sdim 374239313SdimInlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, 375239313Sdim SourceLocation CommandLocEnd, 376243830Sdim unsigned CommandID, 377239313Sdim SourceLocation ArgLocBegin, 378239313Sdim SourceLocation ArgLocEnd, 379239313Sdim StringRef Arg) { 380239313Sdim typedef InlineCommandComment::Argument Argument; 381239313Sdim Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 382239313Sdim ArgLocEnd), 383239313Sdim Arg); 384243830Sdim StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; 385239313Sdim 386239313Sdim return new (Allocator) InlineCommandComment( 387239313Sdim CommandLocBegin, 388239313Sdim CommandLocEnd, 389243830Sdim CommandID, 390239313Sdim getInlineCommandRenderKind(CommandName), 391239313Sdim llvm::makeArrayRef(A, 1)); 392239313Sdim} 393239313Sdim 394239313SdimInlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, 395239313Sdim SourceLocation LocEnd, 396243830Sdim StringRef CommandName) { 397243830Sdim unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID(); 398243830Sdim return actOnUnknownCommand(LocBegin, LocEnd, CommandID); 399243830Sdim} 400243830Sdim 401243830SdimInlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, 402243830Sdim SourceLocation LocEnd, 403243830Sdim unsigned CommandID) { 404239313Sdim ArrayRef<InlineCommandComment::Argument> Args; 405239313Sdim return new (Allocator) InlineCommandComment( 406243830Sdim LocBegin, LocEnd, CommandID, 407239313Sdim InlineCommandComment::RenderNormal, 408239313Sdim Args); 409239313Sdim} 410239313Sdim 411239313SdimTextComment *Sema::actOnText(SourceLocation LocBegin, 412239313Sdim SourceLocation LocEnd, 413239313Sdim StringRef Text) { 414239313Sdim return new (Allocator) TextComment(LocBegin, LocEnd, Text); 415239313Sdim} 416239313Sdim 417239313SdimVerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc, 418243830Sdim unsigned CommandID) { 419243830Sdim StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; 420239313Sdim return new (Allocator) VerbatimBlockComment( 421239313Sdim Loc, 422243830Sdim Loc.getLocWithOffset(1 + CommandName.size()), 423243830Sdim CommandID); 424239313Sdim} 425239313Sdim 426239313SdimVerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc, 427239313Sdim StringRef Text) { 428239313Sdim return new (Allocator) VerbatimBlockLineComment(Loc, Text); 429239313Sdim} 430239313Sdim 431239313Sdimvoid Sema::actOnVerbatimBlockFinish( 432239313Sdim VerbatimBlockComment *Block, 433239313Sdim SourceLocation CloseNameLocBegin, 434239313Sdim StringRef CloseName, 435239313Sdim ArrayRef<VerbatimBlockLineComment *> Lines) { 436239313Sdim Block->setCloseName(CloseName, CloseNameLocBegin); 437239313Sdim Block->setLines(Lines); 438239313Sdim} 439239313Sdim 440239313SdimVerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, 441243830Sdim unsigned CommandID, 442239313Sdim SourceLocation TextBegin, 443239313Sdim StringRef Text) { 444249423Sdim VerbatimLineComment *VL = new (Allocator) VerbatimLineComment( 445239313Sdim LocBegin, 446239313Sdim TextBegin.getLocWithOffset(Text.size()), 447243830Sdim CommandID, 448239313Sdim TextBegin, 449239313Sdim Text); 450249423Sdim checkFunctionDeclVerbatimLine(VL); 451249423Sdim checkContainerDeclVerbatimLine(VL); 452249423Sdim return VL; 453239313Sdim} 454239313Sdim 455239313SdimHTMLStartTagComment *Sema::actOnHTMLStartTagStart(SourceLocation LocBegin, 456239313Sdim StringRef TagName) { 457239313Sdim return new (Allocator) HTMLStartTagComment(LocBegin, TagName); 458239313Sdim} 459239313Sdim 460239313Sdimvoid Sema::actOnHTMLStartTagFinish( 461239313Sdim HTMLStartTagComment *Tag, 462239313Sdim ArrayRef<HTMLStartTagComment::Attribute> Attrs, 463239313Sdim SourceLocation GreaterLoc, 464239313Sdim bool IsSelfClosing) { 465239313Sdim Tag->setAttrs(Attrs); 466239313Sdim Tag->setGreaterLoc(GreaterLoc); 467239313Sdim if (IsSelfClosing) 468239313Sdim Tag->setSelfClosing(); 469239313Sdim else if (!isHTMLEndTagForbidden(Tag->getTagName())) 470239313Sdim HTMLOpenTags.push_back(Tag); 471239313Sdim} 472239313Sdim 473239313SdimHTMLEndTagComment *Sema::actOnHTMLEndTag(SourceLocation LocBegin, 474239313Sdim SourceLocation LocEnd, 475239313Sdim StringRef TagName) { 476239313Sdim HTMLEndTagComment *HET = 477239313Sdim new (Allocator) HTMLEndTagComment(LocBegin, LocEnd, TagName); 478239313Sdim if (isHTMLEndTagForbidden(TagName)) { 479239313Sdim Diag(HET->getLocation(), diag::warn_doc_html_end_forbidden) 480239313Sdim << TagName << HET->getSourceRange(); 481239313Sdim return HET; 482239313Sdim } 483239313Sdim 484239313Sdim bool FoundOpen = false; 485239313Sdim for (SmallVectorImpl<HTMLStartTagComment *>::const_reverse_iterator 486239313Sdim I = HTMLOpenTags.rbegin(), E = HTMLOpenTags.rend(); 487239313Sdim I != E; ++I) { 488239313Sdim if ((*I)->getTagName() == TagName) { 489239313Sdim FoundOpen = true; 490239313Sdim break; 491239313Sdim } 492239313Sdim } 493239313Sdim if (!FoundOpen) { 494239313Sdim Diag(HET->getLocation(), diag::warn_doc_html_end_unbalanced) 495239313Sdim << HET->getSourceRange(); 496239313Sdim return HET; 497239313Sdim } 498239313Sdim 499239313Sdim while (!HTMLOpenTags.empty()) { 500263508Sdim const HTMLStartTagComment *HST = HTMLOpenTags.pop_back_val(); 501239313Sdim StringRef LastNotClosedTagName = HST->getTagName(); 502239313Sdim if (LastNotClosedTagName == TagName) 503239313Sdim break; 504239313Sdim 505239313Sdim if (isHTMLEndTagOptional(LastNotClosedTagName)) 506239313Sdim continue; 507239313Sdim 508239313Sdim bool OpenLineInvalid; 509239313Sdim const unsigned OpenLine = SourceMgr.getPresumedLineNumber( 510239313Sdim HST->getLocation(), 511239313Sdim &OpenLineInvalid); 512239313Sdim bool CloseLineInvalid; 513239313Sdim const unsigned CloseLine = SourceMgr.getPresumedLineNumber( 514239313Sdim HET->getLocation(), 515239313Sdim &CloseLineInvalid); 516239313Sdim 517239313Sdim if (OpenLineInvalid || CloseLineInvalid || OpenLine == CloseLine) 518239313Sdim Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) 519239313Sdim << HST->getTagName() << HET->getTagName() 520239313Sdim << HST->getSourceRange() << HET->getSourceRange(); 521239313Sdim else { 522239313Sdim Diag(HST->getLocation(), diag::warn_doc_html_start_end_mismatch) 523239313Sdim << HST->getTagName() << HET->getTagName() 524239313Sdim << HST->getSourceRange(); 525239313Sdim Diag(HET->getLocation(), diag::note_doc_html_end_tag) 526239313Sdim << HET->getSourceRange(); 527239313Sdim } 528239313Sdim } 529239313Sdim 530239313Sdim return HET; 531239313Sdim} 532239313Sdim 533239313SdimFullComment *Sema::actOnFullComment( 534239313Sdim ArrayRef<BlockContentComment *> Blocks) { 535243830Sdim FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo); 536243830Sdim resolveParamCommandIndexes(FC); 537243830Sdim return FC; 538239313Sdim} 539239313Sdim 540239313Sdimvoid Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { 541243830Sdim if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed) 542243830Sdim return; 543243830Sdim 544239313Sdim ParagraphComment *Paragraph = Command->getParagraph(); 545239313Sdim if (Paragraph->isWhitespace()) { 546239313Sdim SourceLocation DiagLoc; 547239313Sdim if (Command->getNumArgs() > 0) 548239313Sdim DiagLoc = Command->getArgRange(Command->getNumArgs() - 1).getEnd(); 549239313Sdim if (!DiagLoc.isValid()) 550243830Sdim DiagLoc = Command->getCommandNameRange(Traits).getEnd(); 551239313Sdim Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) 552249423Sdim << Command->getCommandMarker() 553243830Sdim << Command->getCommandName(Traits) 554239313Sdim << Command->getSourceRange(); 555239313Sdim } 556239313Sdim} 557239313Sdim 558239313Sdimvoid Sema::checkReturnsCommand(const BlockCommandComment *Command) { 559243830Sdim if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand) 560239313Sdim return; 561239313Sdim if (isFunctionDecl()) { 562239313Sdim if (ThisDeclInfo->ResultType->isVoidType()) { 563239313Sdim unsigned DiagKind; 564243830Sdim switch (ThisDeclInfo->CommentDecl->getKind()) { 565239313Sdim default: 566239313Sdim if (ThisDeclInfo->IsObjCMethod) 567239313Sdim DiagKind = 3; 568239313Sdim else 569239313Sdim DiagKind = 0; 570239313Sdim break; 571239313Sdim case Decl::CXXConstructor: 572239313Sdim DiagKind = 1; 573239313Sdim break; 574239313Sdim case Decl::CXXDestructor: 575239313Sdim DiagKind = 2; 576239313Sdim break; 577239313Sdim } 578239313Sdim Diag(Command->getLocation(), 579239313Sdim diag::warn_doc_returns_attached_to_a_void_function) 580249423Sdim << Command->getCommandMarker() 581243830Sdim << Command->getCommandName(Traits) 582239313Sdim << DiagKind 583239313Sdim << Command->getSourceRange(); 584239313Sdim } 585239313Sdim return; 586239313Sdim } 587249423Sdim else if (isObjCPropertyDecl()) 588249423Sdim return; 589249423Sdim 590239313Sdim Diag(Command->getLocation(), 591239313Sdim diag::warn_doc_returns_not_attached_to_a_function_decl) 592249423Sdim << Command->getCommandMarker() 593243830Sdim << Command->getCommandName(Traits) 594239313Sdim << Command->getSourceRange(); 595239313Sdim} 596239313Sdim 597239313Sdimvoid Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { 598243830Sdim const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID()); 599239313Sdim const BlockCommandComment *PrevCommand = NULL; 600243830Sdim if (Info->IsBriefCommand) { 601239313Sdim if (!BriefCommand) { 602239313Sdim BriefCommand = Command; 603239313Sdim return; 604239313Sdim } 605239313Sdim PrevCommand = BriefCommand; 606249423Sdim } else if (Info->IsHeaderfileCommand) { 607249423Sdim if (!HeaderfileCommand) { 608249423Sdim HeaderfileCommand = Command; 609249423Sdim return; 610249423Sdim } 611249423Sdim PrevCommand = HeaderfileCommand; 612239313Sdim } else { 613239313Sdim // We don't want to check this command for duplicates. 614239313Sdim return; 615239313Sdim } 616243830Sdim StringRef CommandName = Command->getCommandName(Traits); 617243830Sdim StringRef PrevCommandName = PrevCommand->getCommandName(Traits); 618239313Sdim Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) 619249423Sdim << Command->getCommandMarker() 620243830Sdim << CommandName 621239313Sdim << Command->getSourceRange(); 622243830Sdim if (CommandName == PrevCommandName) 623239313Sdim Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) 624249423Sdim << PrevCommand->getCommandMarker() 625243830Sdim << PrevCommandName 626243830Sdim << PrevCommand->getSourceRange(); 627239313Sdim else 628239313Sdim Diag(PrevCommand->getLocation(), 629239313Sdim diag::note_doc_block_command_previous_alias) 630249423Sdim << PrevCommand->getCommandMarker() 631243830Sdim << PrevCommandName 632243830Sdim << CommandName; 633239313Sdim} 634239313Sdim 635243830Sdimvoid Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { 636243830Sdim if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand) 637243830Sdim return; 638243830Sdim 639243830Sdim const Decl *D = ThisDeclInfo->CommentDecl; 640243830Sdim if (!D) 641243830Sdim return; 642243830Sdim 643243830Sdim if (D->hasAttr<DeprecatedAttr>() || 644243830Sdim D->hasAttr<AvailabilityAttr>() || 645243830Sdim D->hasAttr<UnavailableAttr>()) 646243830Sdim return; 647243830Sdim 648243830Sdim Diag(Command->getLocation(), 649243830Sdim diag::warn_doc_deprecated_not_sync) 650243830Sdim << Command->getSourceRange(); 651243830Sdim 652243830Sdim // Try to emit a fixit with a deprecation attribute. 653243830Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 654243830Sdim // Don't emit a Fix-It for non-member function definitions. GCC does not 655243830Sdim // accept attributes on them. 656243830Sdim const DeclContext *Ctx = FD->getDeclContext(); 657243830Sdim if ((!Ctx || !Ctx->isRecord()) && 658243830Sdim FD->doesThisDeclarationHaveABody()) 659243830Sdim return; 660243830Sdim 661243830Sdim StringRef AttributeSpelling = "__attribute__((deprecated))"; 662243830Sdim if (PP) { 663243830Sdim TokenValue Tokens[] = { 664243830Sdim tok::kw___attribute, tok::l_paren, tok::l_paren, 665243830Sdim PP->getIdentifierInfo("deprecated"), 666243830Sdim tok::r_paren, tok::r_paren 667243830Sdim }; 668243830Sdim StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), 669243830Sdim Tokens); 670243830Sdim if (!MacroName.empty()) 671243830Sdim AttributeSpelling = MacroName; 672243830Sdim } 673243830Sdim 674243830Sdim SmallString<64> TextToInsert(" "); 675243830Sdim TextToInsert += AttributeSpelling; 676243830Sdim Diag(FD->getLocEnd(), 677243830Sdim diag::note_add_deprecation_attr) 678243830Sdim << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1), 679243830Sdim TextToInsert); 680243830Sdim } 681243830Sdim} 682243830Sdim 683243830Sdimvoid Sema::resolveParamCommandIndexes(const FullComment *FC) { 684243830Sdim if (!isFunctionDecl()) { 685243830Sdim // We already warned that \\param commands are not attached to a function 686243830Sdim // decl. 687243830Sdim return; 688243830Sdim } 689243830Sdim 690249423Sdim SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands; 691243830Sdim 692243830Sdim // Comment AST nodes that correspond to \c ParamVars for which we have 693243830Sdim // found a \\param command or NULL if no documentation was found so far. 694249423Sdim SmallVector<ParamCommandComment *, 8> ParamVarDocs; 695243830Sdim 696243830Sdim ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); 697243830Sdim ParamVarDocs.resize(ParamVars.size(), NULL); 698243830Sdim 699243830Sdim // First pass over all \\param commands: resolve all parameter names. 700243830Sdim for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end(); 701243830Sdim I != E; ++I) { 702243830Sdim ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I); 703243830Sdim if (!PCC || !PCC->hasParamName()) 704243830Sdim continue; 705243830Sdim StringRef ParamName = PCC->getParamNameAsWritten(); 706243830Sdim 707243830Sdim // Check that referenced parameter name is in the function decl. 708243830Sdim const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, 709243830Sdim ParamVars); 710263508Sdim if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { 711263508Sdim PCC->setIsVarArgParam(); 712263508Sdim continue; 713263508Sdim } 714243830Sdim if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { 715243830Sdim UnresolvedParamCommands.push_back(PCC); 716243830Sdim continue; 717243830Sdim } 718243830Sdim PCC->setParamIndex(ResolvedParamIndex); 719243830Sdim if (ParamVarDocs[ResolvedParamIndex]) { 720243830Sdim SourceRange ArgRange = PCC->getParamNameRange(); 721243830Sdim Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate) 722243830Sdim << ParamName << ArgRange; 723243830Sdim ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; 724243830Sdim Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) 725243830Sdim << PrevCommand->getParamNameRange(); 726243830Sdim } 727243830Sdim ParamVarDocs[ResolvedParamIndex] = PCC; 728243830Sdim } 729243830Sdim 730243830Sdim // Find parameter declarations that have no corresponding \\param. 731249423Sdim SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; 732243830Sdim for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) { 733243830Sdim if (!ParamVarDocs[i]) 734243830Sdim OrphanedParamDecls.push_back(ParamVars[i]); 735243830Sdim } 736243830Sdim 737243830Sdim // Second pass over unresolved \\param commands: do typo correction. 738243830Sdim // Suggest corrections from a set of parameter declarations that have no 739243830Sdim // corresponding \\param. 740243830Sdim for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) { 741243830Sdim const ParamCommandComment *PCC = UnresolvedParamCommands[i]; 742243830Sdim 743243830Sdim SourceRange ArgRange = PCC->getParamNameRange(); 744243830Sdim StringRef ParamName = PCC->getParamNameAsWritten(); 745243830Sdim Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) 746243830Sdim << ParamName << ArgRange; 747243830Sdim 748243830Sdim // All parameters documented -- can't suggest a correction. 749243830Sdim if (OrphanedParamDecls.size() == 0) 750243830Sdim continue; 751243830Sdim 752243830Sdim unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; 753243830Sdim if (OrphanedParamDecls.size() == 1) { 754243830Sdim // If one parameter is not documented then that parameter is the only 755243830Sdim // possible suggestion. 756243830Sdim CorrectedParamIndex = 0; 757243830Sdim } else { 758243830Sdim // Do typo correction. 759243830Sdim CorrectedParamIndex = correctTypoInParmVarReference(ParamName, 760243830Sdim OrphanedParamDecls); 761243830Sdim } 762243830Sdim if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { 763243830Sdim const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex]; 764243830Sdim if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) 765243830Sdim Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) 766243830Sdim << CorrectedII->getName() 767243830Sdim << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); 768243830Sdim } 769243830Sdim } 770243830Sdim} 771243830Sdim 772239313Sdimbool Sema::isFunctionDecl() { 773239313Sdim if (!ThisDeclInfo) 774239313Sdim return false; 775239313Sdim if (!ThisDeclInfo->IsFilled) 776239313Sdim inspectThisDecl(); 777239313Sdim return ThisDeclInfo->getKind() == DeclInfo::FunctionKind; 778239313Sdim} 779239313Sdim 780249423Sdimbool Sema::isAnyFunctionDecl() { 781249423Sdim return isFunctionDecl() && ThisDeclInfo->CurrentDecl && 782249423Sdim isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); 783249423Sdim} 784263508Sdim 785263508Sdimbool Sema::isFunctionOrMethodVariadic() { 786263508Sdim if (!isAnyFunctionDecl() && !isObjCMethodDecl()) 787263508Sdim return false; 788263508Sdim if (const FunctionDecl *FD = 789263508Sdim dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) 790263508Sdim return FD->isVariadic(); 791263508Sdim if (const ObjCMethodDecl *MD = 792263508Sdim dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) 793263508Sdim return MD->isVariadic(); 794263508Sdim return false; 795263508Sdim} 796263508Sdim 797249423Sdimbool Sema::isObjCMethodDecl() { 798249423Sdim return isFunctionDecl() && ThisDeclInfo->CurrentDecl && 799249423Sdim isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl); 800249423Sdim} 801263508Sdim 802249423Sdimbool Sema::isFunctionPointerVarDecl() { 803249423Sdim if (!ThisDeclInfo) 804249423Sdim return false; 805249423Sdim if (!ThisDeclInfo->IsFilled) 806249423Sdim inspectThisDecl(); 807249423Sdim if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) { 808249423Sdim if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) { 809249423Sdim QualType QT = VD->getType(); 810249423Sdim return QT->isFunctionPointerType(); 811249423Sdim } 812249423Sdim } 813249423Sdim return false; 814249423Sdim} 815249423Sdim 816249423Sdimbool Sema::isObjCPropertyDecl() { 817249423Sdim if (!ThisDeclInfo) 818249423Sdim return false; 819249423Sdim if (!ThisDeclInfo->IsFilled) 820249423Sdim inspectThisDecl(); 821249423Sdim return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty; 822249423Sdim} 823249423Sdim 824239313Sdimbool Sema::isTemplateOrSpecialization() { 825239313Sdim if (!ThisDeclInfo) 826239313Sdim return false; 827239313Sdim if (!ThisDeclInfo->IsFilled) 828239313Sdim inspectThisDecl(); 829239313Sdim return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate; 830239313Sdim} 831239313Sdim 832249423Sdimbool Sema::isRecordLikeDecl() { 833249423Sdim if (!ThisDeclInfo) 834249423Sdim return false; 835249423Sdim if (!ThisDeclInfo->IsFilled) 836249423Sdim inspectThisDecl(); 837249423Sdim return isUnionDecl() || isClassOrStructDecl() 838249423Sdim || isObjCInterfaceDecl() || isObjCProtocolDecl(); 839249423Sdim} 840249423Sdim 841249423Sdimbool Sema::isUnionDecl() { 842249423Sdim if (!ThisDeclInfo) 843249423Sdim return false; 844249423Sdim if (!ThisDeclInfo->IsFilled) 845249423Sdim inspectThisDecl(); 846249423Sdim if (const RecordDecl *RD = 847249423Sdim dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl)) 848249423Sdim return RD->isUnion(); 849249423Sdim return false; 850249423Sdim} 851249423Sdim 852249423Sdimbool Sema::isClassOrStructDecl() { 853249423Sdim if (!ThisDeclInfo) 854249423Sdim return false; 855249423Sdim if (!ThisDeclInfo->IsFilled) 856249423Sdim inspectThisDecl(); 857249423Sdim return ThisDeclInfo->CurrentDecl && 858249423Sdim isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && 859249423Sdim !isUnionDecl(); 860249423Sdim} 861263508Sdim 862263508Sdimbool Sema::isClassTemplateDecl() { 863263508Sdim if (!ThisDeclInfo) 864263508Sdim return false; 865263508Sdim if (!ThisDeclInfo->IsFilled) 866263508Sdim inspectThisDecl(); 867263508Sdim return ThisDeclInfo->CurrentDecl && 868263508Sdim (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl)); 869263508Sdim} 870249423Sdim 871263508Sdimbool Sema::isFunctionTemplateDecl() { 872263508Sdim if (!ThisDeclInfo) 873263508Sdim return false; 874263508Sdim if (!ThisDeclInfo->IsFilled) 875263508Sdim inspectThisDecl(); 876263508Sdim return ThisDeclInfo->CurrentDecl && 877263508Sdim (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)); 878263508Sdim} 879263508Sdim 880249423Sdimbool Sema::isObjCInterfaceDecl() { 881249423Sdim if (!ThisDeclInfo) 882249423Sdim return false; 883249423Sdim if (!ThisDeclInfo->IsFilled) 884249423Sdim inspectThisDecl(); 885249423Sdim return ThisDeclInfo->CurrentDecl && 886249423Sdim isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl); 887249423Sdim} 888249423Sdim 889249423Sdimbool Sema::isObjCProtocolDecl() { 890249423Sdim if (!ThisDeclInfo) 891249423Sdim return false; 892249423Sdim if (!ThisDeclInfo->IsFilled) 893249423Sdim inspectThisDecl(); 894249423Sdim return ThisDeclInfo->CurrentDecl && 895249423Sdim isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl); 896249423Sdim} 897249423Sdim 898239313SdimArrayRef<const ParmVarDecl *> Sema::getParamVars() { 899239313Sdim if (!ThisDeclInfo->IsFilled) 900239313Sdim inspectThisDecl(); 901239313Sdim return ThisDeclInfo->ParamVars; 902239313Sdim} 903239313Sdim 904239313Sdimvoid Sema::inspectThisDecl() { 905239313Sdim ThisDeclInfo->fill(); 906239313Sdim} 907239313Sdim 908239313Sdimunsigned Sema::resolveParmVarReference(StringRef Name, 909239313Sdim ArrayRef<const ParmVarDecl *> ParamVars) { 910239313Sdim for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) { 911239313Sdim const IdentifierInfo *II = ParamVars[i]->getIdentifier(); 912239313Sdim if (II && II->getName() == Name) 913239313Sdim return i; 914239313Sdim } 915263508Sdim if (Name == "..." && isFunctionOrMethodVariadic()) 916263508Sdim return ParamCommandComment::VarArgParamIndex; 917239313Sdim return ParamCommandComment::InvalidParamIndex; 918239313Sdim} 919239313Sdim 920239313Sdimnamespace { 921239313Sdimclass SimpleTypoCorrector { 922239313Sdim StringRef Typo; 923239313Sdim const unsigned MaxEditDistance; 924239313Sdim 925239313Sdim const NamedDecl *BestDecl; 926239313Sdim unsigned BestEditDistance; 927239313Sdim unsigned BestIndex; 928239313Sdim unsigned NextIndex; 929239313Sdim 930239313Sdimpublic: 931239313Sdim SimpleTypoCorrector(StringRef Typo) : 932239313Sdim Typo(Typo), MaxEditDistance((Typo.size() + 2) / 3), 933239313Sdim BestDecl(NULL), BestEditDistance(MaxEditDistance + 1), 934239313Sdim BestIndex(0), NextIndex(0) 935239313Sdim { } 936239313Sdim 937239313Sdim void addDecl(const NamedDecl *ND); 938239313Sdim 939239313Sdim const NamedDecl *getBestDecl() const { 940239313Sdim if (BestEditDistance > MaxEditDistance) 941239313Sdim return NULL; 942239313Sdim 943239313Sdim return BestDecl; 944239313Sdim } 945239313Sdim 946239313Sdim unsigned getBestDeclIndex() const { 947239313Sdim assert(getBestDecl()); 948239313Sdim return BestIndex; 949239313Sdim } 950239313Sdim}; 951239313Sdim 952239313Sdimvoid SimpleTypoCorrector::addDecl(const NamedDecl *ND) { 953239313Sdim unsigned CurrIndex = NextIndex++; 954239313Sdim 955239313Sdim const IdentifierInfo *II = ND->getIdentifier(); 956239313Sdim if (!II) 957239313Sdim return; 958239313Sdim 959239313Sdim StringRef Name = II->getName(); 960239313Sdim unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size()); 961239313Sdim if (MinPossibleEditDistance > 0 && 962239313Sdim Typo.size() / MinPossibleEditDistance < 3) 963239313Sdim return; 964239313Sdim 965239313Sdim unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance); 966239313Sdim if (EditDistance < BestEditDistance) { 967239313Sdim BestEditDistance = EditDistance; 968239313Sdim BestDecl = ND; 969239313Sdim BestIndex = CurrIndex; 970239313Sdim } 971239313Sdim} 972239313Sdim} // unnamed namespace 973239313Sdim 974239313Sdimunsigned Sema::correctTypoInParmVarReference( 975239313Sdim StringRef Typo, 976239313Sdim ArrayRef<const ParmVarDecl *> ParamVars) { 977239313Sdim SimpleTypoCorrector Corrector(Typo); 978239313Sdim for (unsigned i = 0, e = ParamVars.size(); i != e; ++i) 979239313Sdim Corrector.addDecl(ParamVars[i]); 980239313Sdim if (Corrector.getBestDecl()) 981239313Sdim return Corrector.getBestDeclIndex(); 982239313Sdim else 983243830Sdim return ParamCommandComment::InvalidParamIndex; 984239313Sdim} 985239313Sdim 986239313Sdimnamespace { 987239313Sdimbool ResolveTParamReferenceHelper( 988239313Sdim StringRef Name, 989239313Sdim const TemplateParameterList *TemplateParameters, 990239313Sdim SmallVectorImpl<unsigned> *Position) { 991239313Sdim for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { 992239313Sdim const NamedDecl *Param = TemplateParameters->getParam(i); 993239313Sdim const IdentifierInfo *II = Param->getIdentifier(); 994239313Sdim if (II && II->getName() == Name) { 995239313Sdim Position->push_back(i); 996239313Sdim return true; 997239313Sdim } 998239313Sdim 999239313Sdim if (const TemplateTemplateParmDecl *TTP = 1000239313Sdim dyn_cast<TemplateTemplateParmDecl>(Param)) { 1001239313Sdim Position->push_back(i); 1002239313Sdim if (ResolveTParamReferenceHelper(Name, TTP->getTemplateParameters(), 1003239313Sdim Position)) 1004239313Sdim return true; 1005239313Sdim Position->pop_back(); 1006239313Sdim } 1007239313Sdim } 1008239313Sdim return false; 1009239313Sdim} 1010239313Sdim} // unnamed namespace 1011239313Sdim 1012239313Sdimbool Sema::resolveTParamReference( 1013239313Sdim StringRef Name, 1014239313Sdim const TemplateParameterList *TemplateParameters, 1015239313Sdim SmallVectorImpl<unsigned> *Position) { 1016239313Sdim Position->clear(); 1017239313Sdim if (!TemplateParameters) 1018239313Sdim return false; 1019239313Sdim 1020239313Sdim return ResolveTParamReferenceHelper(Name, TemplateParameters, Position); 1021239313Sdim} 1022239313Sdim 1023239313Sdimnamespace { 1024239313Sdimvoid CorrectTypoInTParamReferenceHelper( 1025239313Sdim const TemplateParameterList *TemplateParameters, 1026239313Sdim SimpleTypoCorrector &Corrector) { 1027239313Sdim for (unsigned i = 0, e = TemplateParameters->size(); i != e; ++i) { 1028239313Sdim const NamedDecl *Param = TemplateParameters->getParam(i); 1029239313Sdim Corrector.addDecl(Param); 1030239313Sdim 1031239313Sdim if (const TemplateTemplateParmDecl *TTP = 1032239313Sdim dyn_cast<TemplateTemplateParmDecl>(Param)) 1033239313Sdim CorrectTypoInTParamReferenceHelper(TTP->getTemplateParameters(), 1034239313Sdim Corrector); 1035239313Sdim } 1036239313Sdim} 1037239313Sdim} // unnamed namespace 1038239313Sdim 1039239313SdimStringRef Sema::correctTypoInTParamReference( 1040239313Sdim StringRef Typo, 1041239313Sdim const TemplateParameterList *TemplateParameters) { 1042239313Sdim SimpleTypoCorrector Corrector(Typo); 1043239313Sdim CorrectTypoInTParamReferenceHelper(TemplateParameters, Corrector); 1044239313Sdim if (const NamedDecl *ND = Corrector.getBestDecl()) { 1045239313Sdim const IdentifierInfo *II = ND->getIdentifier(); 1046239313Sdim assert(II && "SimpleTypoCorrector should not return this decl"); 1047239313Sdim return II->getName(); 1048239313Sdim } 1049239313Sdim return StringRef(); 1050239313Sdim} 1051239313Sdim 1052239313SdimInlineCommandComment::RenderKind 1053239313SdimSema::getInlineCommandRenderKind(StringRef Name) const { 1054243830Sdim assert(Traits.getCommandInfo(Name)->IsInlineCommand); 1055239313Sdim 1056239313Sdim return llvm::StringSwitch<InlineCommandComment::RenderKind>(Name) 1057239313Sdim .Case("b", InlineCommandComment::RenderBold) 1058239313Sdim .Cases("c", "p", InlineCommandComment::RenderMonospaced) 1059239313Sdim .Cases("a", "e", "em", InlineCommandComment::RenderEmphasized) 1060239313Sdim .Default(InlineCommandComment::RenderNormal); 1061239313Sdim} 1062239313Sdim 1063239313Sdim} // end namespace comments 1064239313Sdim} // end namespace clang 1065239313Sdim 1066