clang API Documentation

CommentBriefParser.cpp
Go to the documentation of this file.
00001 //===--- CommentBriefParser.cpp - Dumb comment parser ---------------------===//
00002 //
00003 //                     The LLVM Compiler Infrastructure
00004 //
00005 // This file is distributed under the University of Illinois Open Source
00006 // License. See LICENSE.TXT for details.
00007 //
00008 //===----------------------------------------------------------------------===//
00009 
00010 #include "clang/AST/CommentBriefParser.h"
00011 #include "clang/AST/CommentCommandTraits.h"
00012 #include "llvm/ADT/StringSwitch.h"
00013 
00014 namespace clang {
00015 namespace comments {
00016 
00017 namespace {
00018 inline bool isWhitespace(char C) {
00019   return C == ' ' || C == '\n' || C == '\r' ||
00020          C == '\t' || C == '\f' || C == '\v';
00021 }
00022 
00023 /// Convert all whitespace into spaces, remove leading and trailing spaces,
00024 /// compress multiple spaces into one.
00025 void cleanupBrief(std::string &S) {
00026   bool PrevWasSpace = true;
00027   std::string::iterator O = S.begin();
00028   for (std::string::iterator I = S.begin(), E = S.end();
00029        I != E; ++I) {
00030     const char C = *I;
00031     if (isWhitespace(C)) {
00032       if (!PrevWasSpace) {
00033         *O++ = ' ';
00034         PrevWasSpace = true;
00035       }
00036       continue;
00037     } else {
00038       *O++ = C;
00039       PrevWasSpace = false;
00040     }
00041   }
00042   if (O != S.begin() && *(O - 1) == ' ')
00043     --O;
00044 
00045   S.resize(O - S.begin());
00046 }
00047 
00048 bool isWhitespace(StringRef Text) {
00049   for (StringRef::const_iterator I = Text.begin(), E = Text.end();
00050        I != E; ++I) {
00051     if (!isWhitespace(*I))
00052       return false;
00053   }
00054   return true;
00055 }
00056 } // unnamed namespace
00057 
00058 BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) :
00059     L(L), Traits(Traits) {
00060   // Get lookahead token.
00061   ConsumeToken();
00062 }
00063 
00064 std::string BriefParser::Parse() {
00065   std::string FirstParagraphOrBrief;
00066   std::string ReturnsParagraph;
00067   bool InFirstParagraph = true;
00068   bool InBrief = false;
00069   bool InReturns = false;
00070 
00071   while (Tok.isNot(tok::eof)) {
00072     if (Tok.is(tok::text)) {
00073       if (InFirstParagraph || InBrief)
00074         FirstParagraphOrBrief += Tok.getText();
00075       else if (InReturns)
00076         ReturnsParagraph += Tok.getText();
00077       ConsumeToken();
00078       continue;
00079     }
00080 
00081     if (Tok.is(tok::backslash_command) || Tok.is(tok::at_command)) {
00082       const CommandInfo *Info = Traits.getCommandInfo(Tok.getCommandID());
00083       if (Info->IsBriefCommand) {
00084         FirstParagraphOrBrief.clear();
00085         InBrief = true;
00086         ConsumeToken();
00087         continue;
00088       }
00089       if (Info->IsReturnsCommand) {
00090         InReturns = true;
00091         InBrief = false;
00092         InFirstParagraph = false;
00093         ReturnsParagraph += "Returns ";
00094         ConsumeToken();
00095         continue;
00096       }
00097       // Block commands implicitly start a new paragraph.
00098       if (Info->IsBlockCommand) {
00099         // We found an implicit paragraph end.
00100         InFirstParagraph = false;
00101         if (InBrief)
00102           break;
00103       }
00104     }
00105 
00106     if (Tok.is(tok::newline)) {
00107       if (InFirstParagraph || InBrief)
00108         FirstParagraphOrBrief += ' ';
00109       else if (InReturns)
00110         ReturnsParagraph += ' ';
00111       ConsumeToken();
00112 
00113       // If the next token is a whitespace only text, ignore it.  Thus we allow
00114       // two paragraphs to be separated by line that has only whitespace in it.
00115       //
00116       // We don't need to add a space to the parsed text because we just added
00117       // a space for the newline.
00118       if (Tok.is(tok::text)) {
00119         if (isWhitespace(Tok.getText()))
00120           ConsumeToken();
00121       }
00122 
00123       if (Tok.is(tok::newline)) {
00124         ConsumeToken();
00125         // We found a paragraph end.  This ends the brief description if
00126         // \\brief command or its equivalent was explicitly used.
00127         // Stop scanning text because an explicit \\brief paragraph is the
00128         // preffered one.
00129         if (InBrief)
00130           break;
00131         // End first paragraph if we found some non-whitespace text.
00132         if (InFirstParagraph && !isWhitespace(FirstParagraphOrBrief))
00133           InFirstParagraph = false;
00134         // End the \\returns paragraph because we found the paragraph end.
00135         InReturns = false;
00136       }
00137       continue;
00138     }
00139 
00140     // We didn't handle this token, so just drop it.
00141     ConsumeToken();
00142   }
00143 
00144   cleanupBrief(FirstParagraphOrBrief);
00145   if (!FirstParagraphOrBrief.empty())
00146     return FirstParagraphOrBrief;
00147 
00148   cleanupBrief(ReturnsParagraph);
00149   return ReturnsParagraph;
00150 }
00151 
00152 } // end namespace comments
00153 } // end namespace clang
00154 
00155