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" 11252723Sdim#include "clang/AST/Attr.h" 12252723Sdim#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" 17245431Sdim#include "clang/Lex/Preprocessor.h" 18252723Sdim#include "llvm/ADT/SmallString.h" 19239313Sdim#include "llvm/ADT/StringSwitch.h" 20239313Sdim 21239313Sdimnamespace clang { 22239313Sdimnamespace comments { 23239313Sdim 24245431Sdimnamespace { 25245431Sdim#include "clang/AST/CommentHTMLTagsProperties.inc" 26245431Sdim} // unnamed namespace 27245431Sdim 28239313SdimSema::Sema(llvm::BumpPtrAllocator &Allocator, const SourceManager &SourceMgr, 29245431Sdim DiagnosticsEngine &Diags, CommandTraits &Traits, 30245431Sdim const Preprocessor *PP) : 31239313Sdim Allocator(Allocator), SourceMgr(SourceMgr), Diags(Diags), Traits(Traits), 32263509Sdim 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; 40245431Sdim ThisDeclInfo->CommentDecl = D; 41239313Sdim ThisDeclInfo->IsFilled = false; 42239313Sdim} 43239313Sdim 44239313SdimParagraphComment *Sema::actOnParagraphComment( 45239313Sdim ArrayRef<InlineContentComment *> Content) { 46239313Sdim return new (Allocator) ParagraphComment(Content); 47239313Sdim} 48239313Sdim 49252723SdimBlockCommandComment *Sema::actOnBlockCommandStart( 50252723Sdim SourceLocation LocBegin, 51252723Sdim SourceLocation LocEnd, 52252723Sdim unsigned CommandID, 53252723Sdim CommandMarkerKind CommandMarker) { 54252723Sdim BlockCommandComment *BC = new (Allocator) BlockCommandComment(LocBegin, LocEnd, 55252723Sdim CommandID, 56252723Sdim CommandMarker); 57252723Sdim checkContainerDecl(BC); 58252723Sdim 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); 72245431Sdim checkDeprecatedCommand(Command); 73239313Sdim} 74239313Sdim 75252723SdimParamCommandComment *Sema::actOnParamCommandStart( 76252723Sdim SourceLocation LocBegin, 77252723Sdim SourceLocation LocEnd, 78252723Sdim unsigned CommandID, 79252723Sdim CommandMarkerKind CommandMarker) { 80239313Sdim ParamCommandComment *Command = 81252723Sdim new (Allocator) ParamCommandComment(LocBegin, LocEnd, CommandID, 82252723Sdim CommandMarker); 83239313Sdim 84239313Sdim if (!isFunctionDecl()) 85239313Sdim Diag(Command->getLocation(), 86239313Sdim diag::warn_doc_param_not_attached_to_a_function_decl) 87252723Sdim << CommandMarker 88245431Sdim << Command->getCommandNameRange(Traits); 89239313Sdim 90239313Sdim return Command; 91239313Sdim} 92239313Sdim 93252723Sdimvoid Sema::checkFunctionDeclVerbatimLine(const BlockCommandComment *Comment) { 94252723Sdim const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); 95252723Sdim if (!Info->IsFunctionDeclarationCommand) 96252723Sdim return; 97252723Sdim 98252723Sdim unsigned DiagSelect; 99252723Sdim switch (Comment->getCommandID()) { 100252723Sdim case CommandTraits::KCI_function: 101263509Sdim DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 1 : 0; 102252723Sdim break; 103252723Sdim case CommandTraits::KCI_functiongroup: 104263509Sdim DiagSelect = (!isAnyFunctionDecl() && !isFunctionTemplateDecl())? 2 : 0; 105252723Sdim break; 106252723Sdim case CommandTraits::KCI_method: 107252723Sdim DiagSelect = !isObjCMethodDecl() ? 3 : 0; 108252723Sdim break; 109252723Sdim case CommandTraits::KCI_methodgroup: 110252723Sdim DiagSelect = !isObjCMethodDecl() ? 4 : 0; 111252723Sdim break; 112252723Sdim case CommandTraits::KCI_callback: 113252723Sdim DiagSelect = !isFunctionPointerVarDecl() ? 5 : 0; 114252723Sdim break; 115252723Sdim default: 116252723Sdim DiagSelect = 0; 117252723Sdim break; 118252723Sdim } 119252723Sdim if (DiagSelect) 120252723Sdim Diag(Comment->getLocation(), diag::warn_doc_function_method_decl_mismatch) 121252723Sdim << Comment->getCommandMarker() 122252723Sdim << (DiagSelect-1) << (DiagSelect-1) 123252723Sdim << Comment->getSourceRange(); 124252723Sdim} 125252723Sdim 126252723Sdimvoid Sema::checkContainerDeclVerbatimLine(const BlockCommandComment *Comment) { 127252723Sdim const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); 128252723Sdim if (!Info->IsRecordLikeDeclarationCommand) 129252723Sdim return; 130252723Sdim unsigned DiagSelect; 131252723Sdim switch (Comment->getCommandID()) { 132252723Sdim case CommandTraits::KCI_class: 133263509Sdim DiagSelect = (!isClassOrStructDecl() && !isClassTemplateDecl()) ? 1 : 0; 134263509Sdim // Allow @class command on @interface declarations. 135263509Sdim // FIXME. Currently, \class and @class are indistinguishable. So, 136263509Sdim // \class is also allowed on an @interface declaration 137263509Sdim if (DiagSelect && Comment->getCommandMarker() && isObjCInterfaceDecl()) 138263509Sdim DiagSelect = 0; 139252723Sdim break; 140252723Sdim case CommandTraits::KCI_interface: 141252723Sdim DiagSelect = !isObjCInterfaceDecl() ? 2 : 0; 142252723Sdim break; 143252723Sdim case CommandTraits::KCI_protocol: 144252723Sdim DiagSelect = !isObjCProtocolDecl() ? 3 : 0; 145252723Sdim break; 146252723Sdim case CommandTraits::KCI_struct: 147252723Sdim DiagSelect = !isClassOrStructDecl() ? 4 : 0; 148252723Sdim break; 149252723Sdim case CommandTraits::KCI_union: 150252723Sdim DiagSelect = !isUnionDecl() ? 5 : 0; 151252723Sdim break; 152252723Sdim default: 153252723Sdim DiagSelect = 0; 154252723Sdim break; 155252723Sdim } 156252723Sdim if (DiagSelect) 157252723Sdim Diag(Comment->getLocation(), diag::warn_doc_api_container_decl_mismatch) 158252723Sdim << Comment->getCommandMarker() 159252723Sdim << (DiagSelect-1) << (DiagSelect-1) 160252723Sdim << Comment->getSourceRange(); 161252723Sdim} 162252723Sdim 163252723Sdimvoid Sema::checkContainerDecl(const BlockCommandComment *Comment) { 164252723Sdim const CommandInfo *Info = Traits.getCommandInfo(Comment->getCommandID()); 165252723Sdim if (!Info->IsRecordLikeDetailCommand || isRecordLikeDecl()) 166252723Sdim return; 167252723Sdim unsigned DiagSelect; 168252723Sdim switch (Comment->getCommandID()) { 169252723Sdim case CommandTraits::KCI_classdesign: 170252723Sdim DiagSelect = 1; 171252723Sdim break; 172252723Sdim case CommandTraits::KCI_coclass: 173252723Sdim DiagSelect = 2; 174252723Sdim break; 175252723Sdim case CommandTraits::KCI_dependency: 176252723Sdim DiagSelect = 3; 177252723Sdim break; 178252723Sdim case CommandTraits::KCI_helper: 179252723Sdim DiagSelect = 4; 180252723Sdim break; 181252723Sdim case CommandTraits::KCI_helperclass: 182252723Sdim DiagSelect = 5; 183252723Sdim break; 184252723Sdim case CommandTraits::KCI_helps: 185252723Sdim DiagSelect = 6; 186252723Sdim break; 187252723Sdim case CommandTraits::KCI_instancesize: 188252723Sdim DiagSelect = 7; 189252723Sdim break; 190252723Sdim case CommandTraits::KCI_ownership: 191252723Sdim DiagSelect = 8; 192252723Sdim break; 193252723Sdim case CommandTraits::KCI_performance: 194252723Sdim DiagSelect = 9; 195252723Sdim break; 196252723Sdim case CommandTraits::KCI_security: 197252723Sdim DiagSelect = 10; 198252723Sdim break; 199252723Sdim case CommandTraits::KCI_superclass: 200252723Sdim DiagSelect = 11; 201252723Sdim break; 202252723Sdim default: 203252723Sdim DiagSelect = 0; 204252723Sdim break; 205252723Sdim } 206252723Sdim if (DiagSelect) 207252723Sdim Diag(Comment->getLocation(), diag::warn_doc_container_decl_mismatch) 208252723Sdim << Comment->getCommandMarker() 209252723Sdim << (DiagSelect-1) 210252723Sdim << Comment->getSourceRange(); 211252723Sdim} 212252723Sdim 213263509Sdim/// \brief Turn a string into the corresponding PassDirection or -1 if it's not 214263509Sdim/// valid. 215263509Sdimstatic int getParamPassDirection(StringRef Arg) { 216263509Sdim return llvm::StringSwitch<int>(Arg) 217263509Sdim .Case("[in]", ParamCommandComment::In) 218263509Sdim .Case("[out]", ParamCommandComment::Out) 219263509Sdim .Cases("[in,out]", "[out,in]", ParamCommandComment::InOut) 220263509Sdim .Default(-1); 221263509Sdim} 222263509Sdim 223239313Sdimvoid Sema::actOnParamCommandDirectionArg(ParamCommandComment *Command, 224239313Sdim SourceLocation ArgLocBegin, 225239313Sdim SourceLocation ArgLocEnd, 226239313Sdim StringRef Arg) { 227239313Sdim std::string ArgLower = Arg.lower(); 228263509Sdim int Direction = getParamPassDirection(ArgLower); 229239313Sdim 230263509Sdim if (Direction == -1) { 231263509Sdim // Try again with whitespace removed. 232263509Sdim ArgLower.erase( 233263509Sdim std::remove_if(ArgLower.begin(), ArgLower.end(), clang::isWhitespace), 234263509Sdim ArgLower.end()); 235263509Sdim Direction = getParamPassDirection(ArgLower); 236239313Sdim 237239313Sdim SourceRange ArgRange(ArgLocBegin, ArgLocEnd); 238263509Sdim if (Direction != -1) { 239263509Sdim const char *FixedName = ParamCommandComment::getDirectionAsString( 240263509Sdim (ParamCommandComment::PassDirection)Direction); 241239313Sdim Diag(ArgLocBegin, diag::warn_doc_param_spaces_in_direction) 242263509Sdim << ArgRange << FixItHint::CreateReplacement(ArgRange, FixedName); 243263509Sdim } else { 244263509Sdim Diag(ArgLocBegin, diag::warn_doc_param_invalid_direction) << ArgRange; 245263509Sdim Direction = ParamCommandComment::In; // Sane fall back. 246263509Sdim } 247239313Sdim } 248263509Sdim Command->setDirection((ParamCommandComment::PassDirection)Direction, 249263509Sdim /*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 276252723SdimTParamCommandComment *Sema::actOnTParamCommandStart( 277252723Sdim SourceLocation LocBegin, 278252723Sdim SourceLocation LocEnd, 279252723Sdim unsigned CommandID, 280252723Sdim CommandMarkerKind CommandMarker) { 281239313Sdim TParamCommandComment *Command = 282252723Sdim new (Allocator) TParamCommandComment(LocBegin, LocEnd, CommandID, 283252723Sdim CommandMarker); 284239313Sdim 285239313Sdim if (!isTemplateOrSpecialization()) 286239313Sdim Diag(Command->getLocation(), 287239313Sdim diag::warn_doc_tparam_not_attached_to_a_template_decl) 288252723Sdim << CommandMarker 289245431Sdim << 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))); 317263509Sdim TParamCommandComment *&PrevCommand = TemplateParameterDocs[Arg]; 318263509Sdim 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 } 325263509Sdim 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, 363245431Sdim unsigned CommandID) { 364239313Sdim ArrayRef<InlineCommandComment::Argument> Args; 365245431Sdim StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; 366239313Sdim return new (Allocator) InlineCommandComment( 367239313Sdim CommandLocBegin, 368239313Sdim CommandLocEnd, 369245431Sdim CommandID, 370239313Sdim getInlineCommandRenderKind(CommandName), 371239313Sdim Args); 372239313Sdim} 373239313Sdim 374239313SdimInlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, 375239313Sdim SourceLocation CommandLocEnd, 376245431Sdim 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); 384245431Sdim StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; 385239313Sdim 386239313Sdim return new (Allocator) InlineCommandComment( 387239313Sdim CommandLocBegin, 388239313Sdim CommandLocEnd, 389245431Sdim CommandID, 390239313Sdim getInlineCommandRenderKind(CommandName), 391239313Sdim llvm::makeArrayRef(A, 1)); 392239313Sdim} 393239313Sdim 394239313SdimInlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, 395239313Sdim SourceLocation LocEnd, 396245431Sdim StringRef CommandName) { 397245431Sdim unsigned CommandID = Traits.registerUnknownCommand(CommandName)->getID(); 398245431Sdim return actOnUnknownCommand(LocBegin, LocEnd, CommandID); 399245431Sdim} 400245431Sdim 401245431SdimInlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, 402245431Sdim SourceLocation LocEnd, 403245431Sdim unsigned CommandID) { 404239313Sdim ArrayRef<InlineCommandComment::Argument> Args; 405239313Sdim return new (Allocator) InlineCommandComment( 406245431Sdim 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, 418245431Sdim unsigned CommandID) { 419245431Sdim StringRef CommandName = Traits.getCommandInfo(CommandID)->Name; 420239313Sdim return new (Allocator) VerbatimBlockComment( 421239313Sdim Loc, 422245431Sdim Loc.getLocWithOffset(1 + CommandName.size()), 423245431Sdim 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, 441245431Sdim unsigned CommandID, 442239313Sdim SourceLocation TextBegin, 443239313Sdim StringRef Text) { 444252723Sdim VerbatimLineComment *VL = new (Allocator) VerbatimLineComment( 445239313Sdim LocBegin, 446239313Sdim TextBegin.getLocWithOffset(Text.size()), 447245431Sdim CommandID, 448239313Sdim TextBegin, 449239313Sdim Text); 450252723Sdim checkFunctionDeclVerbatimLine(VL); 451252723Sdim checkContainerDeclVerbatimLine(VL); 452252723Sdim 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()) { 500263509Sdim 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) { 535245431Sdim FullComment *FC = new (Allocator) FullComment(Blocks, ThisDeclInfo); 536245431Sdim resolveParamCommandIndexes(FC); 537245431Sdim return FC; 538239313Sdim} 539239313Sdim 540239313Sdimvoid Sema::checkBlockCommandEmptyParagraph(BlockCommandComment *Command) { 541245431Sdim if (Traits.getCommandInfo(Command->getCommandID())->IsEmptyParagraphAllowed) 542245431Sdim return; 543245431Sdim 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()) 550245431Sdim DiagLoc = Command->getCommandNameRange(Traits).getEnd(); 551239313Sdim Diag(DiagLoc, diag::warn_doc_block_command_empty_paragraph) 552252723Sdim << Command->getCommandMarker() 553245431Sdim << Command->getCommandName(Traits) 554239313Sdim << Command->getSourceRange(); 555239313Sdim } 556239313Sdim} 557239313Sdim 558239313Sdimvoid Sema::checkReturnsCommand(const BlockCommandComment *Command) { 559245431Sdim if (!Traits.getCommandInfo(Command->getCommandID())->IsReturnsCommand) 560239313Sdim return; 561239313Sdim if (isFunctionDecl()) { 562239313Sdim if (ThisDeclInfo->ResultType->isVoidType()) { 563239313Sdim unsigned DiagKind; 564245431Sdim 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) 580252723Sdim << Command->getCommandMarker() 581245431Sdim << Command->getCommandName(Traits) 582239313Sdim << DiagKind 583239313Sdim << Command->getSourceRange(); 584239313Sdim } 585239313Sdim return; 586239313Sdim } 587252723Sdim else if (isObjCPropertyDecl()) 588252723Sdim return; 589252723Sdim 590239313Sdim Diag(Command->getLocation(), 591239313Sdim diag::warn_doc_returns_not_attached_to_a_function_decl) 592252723Sdim << Command->getCommandMarker() 593245431Sdim << Command->getCommandName(Traits) 594239313Sdim << Command->getSourceRange(); 595239313Sdim} 596239313Sdim 597239313Sdimvoid Sema::checkBlockCommandDuplicate(const BlockCommandComment *Command) { 598245431Sdim const CommandInfo *Info = Traits.getCommandInfo(Command->getCommandID()); 599239313Sdim const BlockCommandComment *PrevCommand = NULL; 600245431Sdim if (Info->IsBriefCommand) { 601239313Sdim if (!BriefCommand) { 602239313Sdim BriefCommand = Command; 603239313Sdim return; 604239313Sdim } 605239313Sdim PrevCommand = BriefCommand; 606252723Sdim } else if (Info->IsHeaderfileCommand) { 607252723Sdim if (!HeaderfileCommand) { 608252723Sdim HeaderfileCommand = Command; 609252723Sdim return; 610252723Sdim } 611252723Sdim PrevCommand = HeaderfileCommand; 612239313Sdim } else { 613239313Sdim // We don't want to check this command for duplicates. 614239313Sdim return; 615239313Sdim } 616245431Sdim StringRef CommandName = Command->getCommandName(Traits); 617245431Sdim StringRef PrevCommandName = PrevCommand->getCommandName(Traits); 618239313Sdim Diag(Command->getLocation(), diag::warn_doc_block_command_duplicate) 619252723Sdim << Command->getCommandMarker() 620245431Sdim << CommandName 621239313Sdim << Command->getSourceRange(); 622245431Sdim if (CommandName == PrevCommandName) 623239313Sdim Diag(PrevCommand->getLocation(), diag::note_doc_block_command_previous) 624252723Sdim << PrevCommand->getCommandMarker() 625245431Sdim << PrevCommandName 626245431Sdim << PrevCommand->getSourceRange(); 627239313Sdim else 628239313Sdim Diag(PrevCommand->getLocation(), 629239313Sdim diag::note_doc_block_command_previous_alias) 630252723Sdim << PrevCommand->getCommandMarker() 631245431Sdim << PrevCommandName 632245431Sdim << CommandName; 633239313Sdim} 634239313Sdim 635245431Sdimvoid Sema::checkDeprecatedCommand(const BlockCommandComment *Command) { 636245431Sdim if (!Traits.getCommandInfo(Command->getCommandID())->IsDeprecatedCommand) 637245431Sdim return; 638245431Sdim 639245431Sdim const Decl *D = ThisDeclInfo->CommentDecl; 640245431Sdim if (!D) 641245431Sdim return; 642245431Sdim 643245431Sdim if (D->hasAttr<DeprecatedAttr>() || 644245431Sdim D->hasAttr<AvailabilityAttr>() || 645245431Sdim D->hasAttr<UnavailableAttr>()) 646245431Sdim return; 647245431Sdim 648245431Sdim Diag(Command->getLocation(), 649245431Sdim diag::warn_doc_deprecated_not_sync) 650245431Sdim << Command->getSourceRange(); 651245431Sdim 652245431Sdim // Try to emit a fixit with a deprecation attribute. 653245431Sdim if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 654245431Sdim // Don't emit a Fix-It for non-member function definitions. GCC does not 655245431Sdim // accept attributes on them. 656245431Sdim const DeclContext *Ctx = FD->getDeclContext(); 657245431Sdim if ((!Ctx || !Ctx->isRecord()) && 658245431Sdim FD->doesThisDeclarationHaveABody()) 659245431Sdim return; 660245431Sdim 661245431Sdim StringRef AttributeSpelling = "__attribute__((deprecated))"; 662245431Sdim if (PP) { 663245431Sdim TokenValue Tokens[] = { 664245431Sdim tok::kw___attribute, tok::l_paren, tok::l_paren, 665245431Sdim PP->getIdentifierInfo("deprecated"), 666245431Sdim tok::r_paren, tok::r_paren 667245431Sdim }; 668245431Sdim StringRef MacroName = PP->getLastMacroWithSpelling(FD->getLocation(), 669245431Sdim Tokens); 670245431Sdim if (!MacroName.empty()) 671245431Sdim AttributeSpelling = MacroName; 672245431Sdim } 673245431Sdim 674245431Sdim SmallString<64> TextToInsert(" "); 675245431Sdim TextToInsert += AttributeSpelling; 676245431Sdim Diag(FD->getLocEnd(), 677245431Sdim diag::note_add_deprecation_attr) 678245431Sdim << FixItHint::CreateInsertion(FD->getLocEnd().getLocWithOffset(1), 679245431Sdim TextToInsert); 680245431Sdim } 681245431Sdim} 682245431Sdim 683245431Sdimvoid Sema::resolveParamCommandIndexes(const FullComment *FC) { 684245431Sdim if (!isFunctionDecl()) { 685245431Sdim // We already warned that \\param commands are not attached to a function 686245431Sdim // decl. 687245431Sdim return; 688245431Sdim } 689245431Sdim 690252723Sdim SmallVector<ParamCommandComment *, 8> UnresolvedParamCommands; 691245431Sdim 692245431Sdim // Comment AST nodes that correspond to \c ParamVars for which we have 693245431Sdim // found a \\param command or NULL if no documentation was found so far. 694252723Sdim SmallVector<ParamCommandComment *, 8> ParamVarDocs; 695245431Sdim 696245431Sdim ArrayRef<const ParmVarDecl *> ParamVars = getParamVars(); 697245431Sdim ParamVarDocs.resize(ParamVars.size(), NULL); 698245431Sdim 699245431Sdim // First pass over all \\param commands: resolve all parameter names. 700245431Sdim for (Comment::child_iterator I = FC->child_begin(), E = FC->child_end(); 701245431Sdim I != E; ++I) { 702245431Sdim ParamCommandComment *PCC = dyn_cast<ParamCommandComment>(*I); 703245431Sdim if (!PCC || !PCC->hasParamName()) 704245431Sdim continue; 705245431Sdim StringRef ParamName = PCC->getParamNameAsWritten(); 706245431Sdim 707245431Sdim // Check that referenced parameter name is in the function decl. 708245431Sdim const unsigned ResolvedParamIndex = resolveParmVarReference(ParamName, 709245431Sdim ParamVars); 710263509Sdim if (ResolvedParamIndex == ParamCommandComment::VarArgParamIndex) { 711263509Sdim PCC->setIsVarArgParam(); 712263509Sdim continue; 713263509Sdim } 714245431Sdim if (ResolvedParamIndex == ParamCommandComment::InvalidParamIndex) { 715245431Sdim UnresolvedParamCommands.push_back(PCC); 716245431Sdim continue; 717245431Sdim } 718245431Sdim PCC->setParamIndex(ResolvedParamIndex); 719245431Sdim if (ParamVarDocs[ResolvedParamIndex]) { 720245431Sdim SourceRange ArgRange = PCC->getParamNameRange(); 721245431Sdim Diag(ArgRange.getBegin(), diag::warn_doc_param_duplicate) 722245431Sdim << ParamName << ArgRange; 723245431Sdim ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex]; 724245431Sdim Diag(PrevCommand->getLocation(), diag::note_doc_param_previous) 725245431Sdim << PrevCommand->getParamNameRange(); 726245431Sdim } 727245431Sdim ParamVarDocs[ResolvedParamIndex] = PCC; 728245431Sdim } 729245431Sdim 730245431Sdim // Find parameter declarations that have no corresponding \\param. 731252723Sdim SmallVector<const ParmVarDecl *, 8> OrphanedParamDecls; 732245431Sdim for (unsigned i = 0, e = ParamVarDocs.size(); i != e; ++i) { 733245431Sdim if (!ParamVarDocs[i]) 734245431Sdim OrphanedParamDecls.push_back(ParamVars[i]); 735245431Sdim } 736245431Sdim 737245431Sdim // Second pass over unresolved \\param commands: do typo correction. 738245431Sdim // Suggest corrections from a set of parameter declarations that have no 739245431Sdim // corresponding \\param. 740245431Sdim for (unsigned i = 0, e = UnresolvedParamCommands.size(); i != e; ++i) { 741245431Sdim const ParamCommandComment *PCC = UnresolvedParamCommands[i]; 742245431Sdim 743245431Sdim SourceRange ArgRange = PCC->getParamNameRange(); 744245431Sdim StringRef ParamName = PCC->getParamNameAsWritten(); 745245431Sdim Diag(ArgRange.getBegin(), diag::warn_doc_param_not_found) 746245431Sdim << ParamName << ArgRange; 747245431Sdim 748245431Sdim // All parameters documented -- can't suggest a correction. 749245431Sdim if (OrphanedParamDecls.size() == 0) 750245431Sdim continue; 751245431Sdim 752245431Sdim unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex; 753245431Sdim if (OrphanedParamDecls.size() == 1) { 754245431Sdim // If one parameter is not documented then that parameter is the only 755245431Sdim // possible suggestion. 756245431Sdim CorrectedParamIndex = 0; 757245431Sdim } else { 758245431Sdim // Do typo correction. 759245431Sdim CorrectedParamIndex = correctTypoInParmVarReference(ParamName, 760245431Sdim OrphanedParamDecls); 761245431Sdim } 762245431Sdim if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) { 763245431Sdim const ParmVarDecl *CorrectedPVD = OrphanedParamDecls[CorrectedParamIndex]; 764245431Sdim if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier()) 765245431Sdim Diag(ArgRange.getBegin(), diag::note_doc_param_name_suggestion) 766245431Sdim << CorrectedII->getName() 767245431Sdim << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName()); 768245431Sdim } 769245431Sdim } 770245431Sdim} 771245431Sdim 772239313Sdimbool Sema::isFunctionDecl() { 773239313Sdim if (!ThisDeclInfo) 774239313Sdim return false; 775239313Sdim if (!ThisDeclInfo->IsFilled) 776239313Sdim inspectThisDecl(); 777239313Sdim return ThisDeclInfo->getKind() == DeclInfo::FunctionKind; 778239313Sdim} 779239313Sdim 780252723Sdimbool Sema::isAnyFunctionDecl() { 781252723Sdim return isFunctionDecl() && ThisDeclInfo->CurrentDecl && 782252723Sdim isa<FunctionDecl>(ThisDeclInfo->CurrentDecl); 783252723Sdim} 784263509Sdim 785263509Sdimbool Sema::isFunctionOrMethodVariadic() { 786263509Sdim if (!isAnyFunctionDecl() && !isObjCMethodDecl()) 787263509Sdim return false; 788263509Sdim if (const FunctionDecl *FD = 789263509Sdim dyn_cast<FunctionDecl>(ThisDeclInfo->CurrentDecl)) 790263509Sdim return FD->isVariadic(); 791263509Sdim if (const ObjCMethodDecl *MD = 792263509Sdim dyn_cast<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl)) 793263509Sdim return MD->isVariadic(); 794263509Sdim return false; 795263509Sdim} 796263509Sdim 797252723Sdimbool Sema::isObjCMethodDecl() { 798252723Sdim return isFunctionDecl() && ThisDeclInfo->CurrentDecl && 799252723Sdim isa<ObjCMethodDecl>(ThisDeclInfo->CurrentDecl); 800252723Sdim} 801263509Sdim 802252723Sdimbool Sema::isFunctionPointerVarDecl() { 803252723Sdim if (!ThisDeclInfo) 804252723Sdim return false; 805252723Sdim if (!ThisDeclInfo->IsFilled) 806252723Sdim inspectThisDecl(); 807252723Sdim if (ThisDeclInfo->getKind() == DeclInfo::VariableKind) { 808252723Sdim if (const VarDecl *VD = dyn_cast_or_null<VarDecl>(ThisDeclInfo->CurrentDecl)) { 809252723Sdim QualType QT = VD->getType(); 810252723Sdim return QT->isFunctionPointerType(); 811252723Sdim } 812252723Sdim } 813252723Sdim return false; 814252723Sdim} 815252723Sdim 816252723Sdimbool Sema::isObjCPropertyDecl() { 817252723Sdim if (!ThisDeclInfo) 818252723Sdim return false; 819252723Sdim if (!ThisDeclInfo->IsFilled) 820252723Sdim inspectThisDecl(); 821252723Sdim return ThisDeclInfo->CurrentDecl->getKind() == Decl::ObjCProperty; 822252723Sdim} 823252723Sdim 824239313Sdimbool Sema::isTemplateOrSpecialization() { 825239313Sdim if (!ThisDeclInfo) 826239313Sdim return false; 827239313Sdim if (!ThisDeclInfo->IsFilled) 828239313Sdim inspectThisDecl(); 829239313Sdim return ThisDeclInfo->getTemplateKind() != DeclInfo::NotTemplate; 830239313Sdim} 831239313Sdim 832252723Sdimbool Sema::isRecordLikeDecl() { 833252723Sdim if (!ThisDeclInfo) 834252723Sdim return false; 835252723Sdim if (!ThisDeclInfo->IsFilled) 836252723Sdim inspectThisDecl(); 837252723Sdim return isUnionDecl() || isClassOrStructDecl() 838252723Sdim || isObjCInterfaceDecl() || isObjCProtocolDecl(); 839252723Sdim} 840252723Sdim 841252723Sdimbool Sema::isUnionDecl() { 842252723Sdim if (!ThisDeclInfo) 843252723Sdim return false; 844252723Sdim if (!ThisDeclInfo->IsFilled) 845252723Sdim inspectThisDecl(); 846252723Sdim if (const RecordDecl *RD = 847252723Sdim dyn_cast_or_null<RecordDecl>(ThisDeclInfo->CurrentDecl)) 848252723Sdim return RD->isUnion(); 849252723Sdim return false; 850252723Sdim} 851252723Sdim 852252723Sdimbool Sema::isClassOrStructDecl() { 853252723Sdim if (!ThisDeclInfo) 854252723Sdim return false; 855252723Sdim if (!ThisDeclInfo->IsFilled) 856252723Sdim inspectThisDecl(); 857252723Sdim return ThisDeclInfo->CurrentDecl && 858252723Sdim isa<RecordDecl>(ThisDeclInfo->CurrentDecl) && 859252723Sdim !isUnionDecl(); 860252723Sdim} 861263509Sdim 862263509Sdimbool Sema::isClassTemplateDecl() { 863263509Sdim if (!ThisDeclInfo) 864263509Sdim return false; 865263509Sdim if (!ThisDeclInfo->IsFilled) 866263509Sdim inspectThisDecl(); 867263509Sdim return ThisDeclInfo->CurrentDecl && 868263509Sdim (isa<ClassTemplateDecl>(ThisDeclInfo->CurrentDecl)); 869263509Sdim} 870252723Sdim 871263509Sdimbool Sema::isFunctionTemplateDecl() { 872263509Sdim if (!ThisDeclInfo) 873263509Sdim return false; 874263509Sdim if (!ThisDeclInfo->IsFilled) 875263509Sdim inspectThisDecl(); 876263509Sdim return ThisDeclInfo->CurrentDecl && 877263509Sdim (isa<FunctionTemplateDecl>(ThisDeclInfo->CurrentDecl)); 878263509Sdim} 879263509Sdim 880252723Sdimbool Sema::isObjCInterfaceDecl() { 881252723Sdim if (!ThisDeclInfo) 882252723Sdim return false; 883252723Sdim if (!ThisDeclInfo->IsFilled) 884252723Sdim inspectThisDecl(); 885252723Sdim return ThisDeclInfo->CurrentDecl && 886252723Sdim isa<ObjCInterfaceDecl>(ThisDeclInfo->CurrentDecl); 887252723Sdim} 888252723Sdim 889252723Sdimbool Sema::isObjCProtocolDecl() { 890252723Sdim if (!ThisDeclInfo) 891252723Sdim return false; 892252723Sdim if (!ThisDeclInfo->IsFilled) 893252723Sdim inspectThisDecl(); 894252723Sdim return ThisDeclInfo->CurrentDecl && 895252723Sdim isa<ObjCProtocolDecl>(ThisDeclInfo->CurrentDecl); 896252723Sdim} 897252723Sdim 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 } 915263509Sdim if (Name == "..." && isFunctionOrMethodVariadic()) 916263509Sdim 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 983245431Sdim 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 { 1054245431Sdim 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