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 { isWhitespace(char C)18inline 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. cleanupBrief(std::string & S)25void 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 isWhitespace(StringRef Text)48bool 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 BriefParser(Lexer & L,const CommandTraits & Traits)58BriefParser::BriefParser(Lexer &L, const CommandTraits &Traits) : 59 L(L), Traits(Traits) { 60 // Get lookahead token. 61 ConsumeToken(); 62 } 63 Parse()64std::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