clang API Documentation
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