Home | History | Annotate | Download | only in AST
      1 //===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===//
      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 
     10 #include "clang/AST/CommentBriefParser.h"
     11 #include "clang/AST/CommentCommandTraits.h"
     12 #include "llvm/ADT/StringSwitch.h"
     13 
     14 namespace clang {
     15 namespace comments {
     16 
     17 namespace {
     18 inline bool isWhitespace(char C) {
     19   return C == ' ' || C == '\n' || C == '\r' ||
     20          C == '\t' || C == '\f' || C == '\v';
     21 }
     22 
     23 /// Convert all whitespace into spaces, remove leading and trailing spaces,
     24 /// compress multiple spaces into one.
     25 void cleanupBrief(std::string &S) {
     26   bool PrevWasSpace = true;
     27   std::string::iterator O = S.begin();
     28   for (std::string::iterator I = S.begin(), E = S.end();
     29        I != E; ++I) {
     30     const char C = *I;
     31     if (isWhitespace(C)) {
     32       if (!PrevWasSpace) {
     33         *O++ = ' ';
     34         PrevWasSpace = true;
     35       }
     36       continue;
     37     } else {
     38       *O++ = C;
     39       PrevWasSpace = false;
     40     }
     41   }
     42   if (O != S.begin() && *(O - 1) == ' ')
     43     --O;
     44 
     45   S.resize(O - S.begin());
     46 }
     47 
     48 bool isWhitespace(StringRef Text) {
     49   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
     50        I != E; ++I) {
     51     if (!isWhitespace(*I))
     52       return false;
     53   }
     54   return true;
     55 }
     56 } // unnamed namespace
     57 
     58 BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) :
     59     L(L), Traits(Traits) {
     60   // Get lookahead token.
     61   ConsumeToken();
     62 }
     63 
     64 std::string BriefParser::Parse() {
     65   std::string FirstParagraphOrBrief;
     66   std::string ReturnsParagraph;
     67   bool InFirstParagraph = true;
     68   bool InBrief = false;
     69   bool InReturns = false;
     70 
     71   while (Tok.isNot(tok::eof)) {
     72     if (Tok.is(tok::text)) {
     73       if (InFirstParagraph || InBrief)
     74         FirstParagraphOrBrief += Tok.getText();
     75       else if (InReturns)
     76         ReturnsParagraph += Tok.getText();
     77       ConsumeToken();
     78       continue;
     79     }
     80 
     81     if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
     82       const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
     83       if (Info->IsBriefCommand) {
     84         FirstParagraphOrBrief.clear();
     85         InBrief = true;
     86         ConsumeToken();
     87         continue;
     88       }
     89       if (Info->IsReturnsCommand) {
     90         InReturns = true;
     91         InBrief = false;
     92         InFirstParagraph = false;
     93         ReturnsParagraph += "Returns ";
     94         ConsumeToken();
     95         continue;
     96       }
     97       // Block commands implicitly start a new paragraph.
     98       if (Info->IsBlockCommand) {
     99         // We found an implicit paragraph end.
    100         InFirstParagraph = false;
    101         if (InBrief)
    102           break;
    103       }
    104     }
    105 
    106     if (Tok.is(tok::newline)) {
    107       if (InFirstParagraph || InBrief)
    108         FirstParagraphOrBrief += ' ';
    109       else if (InReturns)
    110         ReturnsParagraph += ' ';
    111       ConsumeToken();
    112 
    113       // If the next token is a whitespace only text, ignore it.  Thus we allow
    114       // two paragraphs to be separated by line that has only whitespace in it.
    115       //
    116       // We don't need to add a space to the parsed text because we just added
    117       // a space for the newline.
    118       if (Tok.is(tok::text)) {
    119         if (isWhitespace(Tok.getText()))
    120           ConsumeToken();
    121       }
    122 
    123       if (Tok.is(tok::newline)) {
    124         ConsumeToken();
    125         // We found a paragraph end.  This ends the brief description if
    126         // \\brief command or its equivalent was explicitly used.
    127         // Stop scanning text because an explicit \\brief paragraph is the
    128         // preffered one.
    129         if (InBrief)
    130           break;
    131         // End first paragraph if we found some non-whitespace text.
    132         if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief))
    133           InFirstParagraph = false;
    134         // End the \\returns paragraph because we found the paragraph end.
    135         InReturns = false;
    136       }
    137       continue;
    138     }
    139 
    140     // We didn't handle this token, so just drop it.
    141     ConsumeToken();
    142   }
    143 
    144   cleanupBrief(FirstParagraphOrBrief);
    145   if (!FirstParagraphOrBrief.empty())
    146     return FirstParagraphOrBrief;
    147 
    148   cleanupBrief(ReturnsParagraph);
    149   return ReturnsParagraph;
    150 }
    151 
    152 } // end namespace comments
    153 } // end namespace clang
    154 
    155 
    156