CommentSema.cpp 29 KB

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