diff options
Diffstat (limited to 'clang/lib/AST/CommentBriefParser.cpp')
| -rw-r--r-- | clang/lib/AST/CommentBriefParser.cpp | 153 | 
1 files changed, 153 insertions, 0 deletions
| diff --git a/clang/lib/AST/CommentBriefParser.cpp b/clang/lib/AST/CommentBriefParser.cpp new file mode 100644 index 000000000000..2b648cbb1d4b --- /dev/null +++ b/clang/lib/AST/CommentBriefParser.cpp @@ -0,0 +1,153 @@ +//===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/CommentBriefParser.h" +#include "clang/AST/CommentCommandTraits.h" + +namespace clang { +namespace comments { + +namespace { +inline bool isWhitespace(char C) { +  return C == ' ' || C == '\n' || C == '\r' || +         C == '\t' || C == '\f' || C == '\v'; +} + +/// Convert all whitespace into spaces, remove leading and trailing spaces, +/// compress multiple spaces into one. +void cleanupBrief(std::string &S) { +  bool PrevWasSpace = true; +  std::string::iterator O = S.begin(); +  for (std::string::iterator I = S.begin(), E = S.end(); +       I != E; ++I) { +    const char C = *I; +    if (isWhitespace(C)) { +      if (!PrevWasSpace) { +        *O++ = ' '; +        PrevWasSpace = true; +      } +      continue; +    } else { +      *O++ = C; +      PrevWasSpace = false; +    } +  } +  if (O != S.begin() && *(O - 1) == ' ') +    --O; + +  S.resize(O - S.begin()); +} + +bool isWhitespace(StringRef Text) { +  for (StringRef::const_iterator I = Text.begin(), E = Text.end(); +       I != E; ++I) { +    if (!isWhitespace(*I)) +      return false; +  } +  return true; +} +} // unnamed namespace + +BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) : +    L(L), Traits(Traits) { +  // Get lookahead token. +  ConsumeToken(); +} + +std::string BriefParser::Parse() { +  std::string FirstParagraphOrBrief; +  std::string ReturnsParagraph; +  bool InFirstParagraph = true; +  bool InBrief = false; +  bool InReturns = false; + +  while (Tok.isNot(tok::eof)) { +    if (Tok.is(tok::text)) { +      if (InFirstParagraph || InBrief) +        FirstParagraphOrBrief += Tok.getText(); +      else if (InReturns) +        ReturnsParagraph += Tok.getText(); +      ConsumeToken(); +      continue; +    } + +    if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) { +      const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID()); +      if (Info->IsBriefCommand) { +        FirstParagraphOrBrief.clear(); +        InBrief = true; +        ConsumeToken(); +        continue; +      } +      if (Info->IsReturnsCommand) { +        InReturns = true; +        InBrief = false; +        InFirstParagraph = false; +        ReturnsParagraph += "Returns "; +        ConsumeToken(); +        continue; +      } +      // Block commands implicitly start a new paragraph. +      if (Info->IsBlockCommand) { +        // We found an implicit paragraph end. +        InFirstParagraph = false; +        if (InBrief) +          break; +      } +    } + +    if (Tok.is(tok::newline)) { +      if (InFirstParagraph || InBrief) +        FirstParagraphOrBrief += ' '; +      else if (InReturns) +        ReturnsParagraph += ' '; +      ConsumeToken(); + +      // If the next token is a whitespace only text, ignore it.  Thus we allow +      // two paragraphs to be separated by line that has only whitespace in it. +      // +      // We don't need to add a space to the parsed text because we just added +      // a space for the newline. +      if (Tok.is(tok::text)) { +        if (isWhitespace(Tok.getText())) +          ConsumeToken(); +      } + +      if (Tok.is(tok::newline)) { +        ConsumeToken(); +        // We found a paragraph end.  This ends the brief description if +        // \command or its equivalent was explicitly used. +        // Stop scanning text because an explicit \paragraph is the +        // preffered one. +        if (InBrief) +          break; +        // End first paragraph if we found some non-whitespace text. +        if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief)) +          InFirstParagraph = false; +        // End the \\returns paragraph because we found the paragraph end. +        InReturns = false; +      } +      continue; +    } + +    // We didn't handle this token, so just drop it. +    ConsumeToken(); +  } + +  cleanupBrief(FirstParagraphOrBrief); +  if (!FirstParagraphOrBrief.empty()) +    return FirstParagraphOrBrief; + +  cleanupBrief(ReturnsParagraph); +  return ReturnsParagraph; +} + +} // end namespace comments +} // end namespace clang + + | 
