<html><head><meta http-equiv="Content-Type" content="text/html charset=us-ascii"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><br><div><div>On May 8, 2013, at 12:42 PM, Dmitri Gribenko <<a href="mailto:gribozavr@gmail.com">gribozavr@gmail.com</a>> wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">On Wed, May 8, 2013 at 10:21 PM, Fariborz Jahanian <<a href="mailto:fjahanian@apple.com">fjahanian@apple.com</a>> wrote:<br><blockquote type="cite">Author: fjahanian<br>Date: Wed May  8 14:21:00 2013<br>New Revision: 181458<br><br>URL: <a href="http://llvm.org/viewvc/llvm-project?rev=181458&view=rev">http://llvm.org/viewvc/llvm-project?rev=181458&view=rev</a><br>Log:<br>documentation parsing. Patch to do typo correction for<br>documentation commands. Patch was reviewed, along with<br>great suggestions for improvement, by Doug.<br>// <a href="rdar://12381408">rdar://12381408</a><br><br>Modified:<br>   cfe/trunk/include/clang/AST/CommentCommandTraits.h<br>   cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td<br>   cfe/trunk/lib/AST/CommentCommandTraits.cpp<br>   cfe/trunk/lib/AST/CommentLexer.cpp<br>   cfe/trunk/test/Sema/warn-documentation-fixits.cpp<br><br>Modified: cfe/trunk/include/clang/AST/CommentCommandTraits.h<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CommentCommandTraits.h?rev=181458&r1=181457&r2=181458&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/CommentCommandTraits.h?rev=181458&r1=181457&r2=181458&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/AST/CommentCommandTraits.h (original)<br>+++ cfe/trunk/include/clang/AST/CommentCommandTraits.h Wed May  8 14:21:00 2013<br>@@ -142,6 +142,8 @@ public:<br>    llvm_unreachable("the command should be known");<br>  }<br><br>+  const CommandInfo *getTypoCorrectCommandInfo(StringRef Typo) const;<br>+<br>  const CommandInfo *getCommandInfo(unsigned CommandID) const;<br><br>  const CommandInfo *registerUnknownCommand(StringRef CommandName);<br><br>Modified: cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td?rev=181458&r1=181457&r2=181458&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td?rev=181458&r1=181457&r2=181458&view=diff</a><br>==============================================================================<br>--- cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td (original)<br>+++ cfe/trunk/include/clang/Basic/DiagnosticCommentKinds.td Wed May  8 14:21:00 2013<br>@@ -159,5 +159,9 @@ def warn_verbatim_block_end_without_star<br>def warn_unknown_comment_command_name : Warning<<br>  "unknown command tag name">, InGroup<Documentation>, DefaultIgnore;<br><br>+def warn_correct_comment_command_name : Warning<<br>+  "unknown command tag name '%0'; did you mean '%1'?">,<br>+  InGroup<Documentation>;<br>+<br>} // end of documentation issue category<br>} // end of AST component<br><br>Modified: cfe/trunk/lib/AST/CommentCommandTraits.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentCommandTraits.cpp?rev=181458&r1=181457&r2=181458&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentCommandTraits.cpp?rev=181458&r1=181457&r2=181458&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/CommentCommandTraits.cpp (original)<br>+++ cfe/trunk/lib/AST/CommentCommandTraits.cpp Wed May  8 14:21:00 2013<br>@@ -43,6 +43,33 @@ const CommandInfo *CommandTraits::getCom<br>  return getRegisteredCommandInfo(CommandID);<br>}<br><br>+const CommandInfo *<br>+CommandTraits::getTypoCorrectCommandInfo(StringRef Typo) const {<br>+  const unsigned MaxEditDistance = 1;<br>+  unsigned BestEditDistance = MaxEditDistance + 1;<br>+  SmallVector<const CommandInfo *, 2> BestCommand;<br>+<br>+  int NumOfCommands = sizeof(Commands) / sizeof(CommandInfo);<br>+  for (int i = 0; i < NumOfCommands; i++) {<br>+    StringRef Name = Commands[i].Name;<br></blockquote><br>This loop should also check dynamically registered commands.<br></div></blockquote><div><br></div>Ah, good catch.</div><div><br><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><blockquote type="cite">+    unsigned MinPossibleEditDistance = abs((int)Name.size() - (int)Typo.size());<br>+    if (MinPossibleEditDistance > 0 &&<br>+        Typo.size() / MinPossibleEditDistance < 1)<br>+      continue;<br>+    unsigned EditDistance = Typo.edit_distance(Name, true, MaxEditDistance);<br>+    if (EditDistance > MaxEditDistance)<br>+      continue;<br>+    if (EditDistance == BestEditDistance)<br>+      BestCommand.push_back(&Commands[i]);<br>+    else if (EditDistance < BestEditDistance) {<br>+      BestCommand.clear();<br>+      BestCommand.push_back(&Commands[i]);<br>+      BestEditDistance = EditDistance;<br>+    }<br>+  }<br>+  return (BestCommand.size() != 1) ? NULL : BestCommand[0];<br>+}<br>+<br>CommandInfo *CommandTraits::createCommandInfoWithName(StringRef CommandName) {<br>  char *Name = Allocator.Allocate<char>(CommandName.size() + 1);<br>  memcpy(Name, CommandName.data(), CommandName.size());<br><br>Modified: cfe/trunk/lib/AST/CommentLexer.cpp<br>URL: <a href="http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentLexer.cpp?rev=181458&r1=181457&r2=181458&view=diff">http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/CommentLexer.cpp?rev=181458&r1=181457&r2=181458&view=diff</a><br>==============================================================================<br>--- cfe/trunk/lib/AST/CommentLexer.cpp (original)<br>+++ cfe/trunk/lib/AST/CommentLexer.cpp Wed May  8 14:21:00 2013<br>@@ -265,6 +265,7 @@ const char *findCCommentEnd(const char *<br>  }<br>  llvm_unreachable("buffer end hit before '*/' was seen");<br>}<br>+<br>} // unnamed namespace<br><br>void Lexer::lexCommentText(Token &T) {<br>@@ -354,8 +355,17 @@ void Lexer::lexCommentText(Token &T) {<br>        if (!Info) {<br>          formTokenWithChars(T, TokenPtr, tok::unknown_command);<br>          T.setUnknownCommandName(CommandName);<br>-          Diag(T.getLocation(), diag::warn_unknown_comment_command_name);<br>-          return;<br>+          if (Info = Traits.getTypoCorrectCommandInfo(CommandName)) {<br>+            StringRef CorrectedName = Info->Name;<br>+            SourceRange CommandRange(T.getLocation().getLocWithOffset(1),<br>+                                     T.getEndLocation());<br>+            Diag(T.getLocation(), diag::warn_correct_comment_command_name)<br>+              << CommandName << CorrectedName<br>+              << FixItHint::CreateReplacement(CommandRange, CorrectedName);<br></blockquote><br>We recover by assuming that the user wanted this correction.  What if<br>they did not?..</div></blockquote><div><br></div><div>That's the way Fix-Its are meant to work: we suggest something when we have a high level of confidence in it, and continue on as if the user had typed what we suggested.</div><div><br></div><blockquote type="cite"><div style="letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;">  (But I can only imagine such situation only for<br>external users who use comment parsing for something non-Doxygen.)<br></div></blockquote></div><div><br></div><div>This is what -fcomment-block-comments=<blah> is for, right?</div><br><div><span class="Apple-tab-span" style="white-space:pre">       </span>- Doug</div><div><span class="Apple-tab-span" style="white-space:pre">       </span></div></body></html>