1 //===--- CommentSema.cpp - Doxygen comment semantic analysis --------------===// 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/CommentSema.h" 11 #include "llvm/ADT/StringSwitch.h" 12 13 namespace clang { 14 namespace comments { 15 16 Sema::Sema(llvm::BumpPtrAllocator &Allocator) : 17 Allocator(Allocator) { 18 } 19 20 ParagraphComment *Sema::actOnParagraphComment( 21 ArrayRef<InlineContentComment *> Content) { 22 return new (Allocator) ParagraphComment(Content); 23 } 24 25 BlockCommandComment *Sema::actOnBlockCommandStart(SourceLocation LocBegin, 26 SourceLocation LocEnd, 27 StringRef Name) { 28 return new (Allocator) BlockCommandComment(LocBegin, LocEnd, Name); 29 } 30 31 BlockCommandComment *Sema::actOnBlockCommandArgs( 32 BlockCommandComment *Command, 33 ArrayRef<BlockCommandComment::Argument> Args) { 34 Command->setArgs(Args); 35 return Command; 36 } 37 38 BlockCommandComment *Sema::actOnBlockCommandFinish( 39 BlockCommandComment *Command, 40 ParagraphComment *Paragraph) { 41 Command->setParagraph(Paragraph); 42 return Command; 43 } 44 45 ParamCommandComment *Sema::actOnParamCommandStart(SourceLocation LocBegin, 46 SourceLocation LocEnd, 47 StringRef Name) { 48 return new (Allocator) ParamCommandComment(LocBegin, LocEnd, Name); 49 } 50 51 ParamCommandComment *Sema::actOnParamCommandArg(ParamCommandComment *Command, 52 SourceLocation ArgLocBegin, 53 SourceLocation ArgLocEnd, 54 StringRef Arg, 55 bool IsDirection) { 56 if (IsDirection) { 57 ParamCommandComment::PassDirection Direction; 58 std::string ArgLower = Arg.lower(); 59 // TODO: optimize: lower Name first (need an API in SmallString for that), 60 // after that StringSwitch. 61 if (ArgLower == "[in]") 62 Direction = ParamCommandComment::In; 63 else if (ArgLower == "[out]") 64 Direction = ParamCommandComment::Out; 65 else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") 66 Direction = ParamCommandComment::InOut; 67 else { 68 // Remove spaces. 69 std::string::iterator O = ArgLower.begin(); 70 for (std::string::iterator I = ArgLower.begin(), E = ArgLower.end(); 71 I != E; ++I) { 72 const char C = *I; 73 if (C != ' ' && C != '\n' && C != '\r' && 74 C != '\t' && C != '\v' && C != '\f') 75 *O++ = C; 76 } 77 ArgLower.resize(O - ArgLower.begin()); 78 79 bool RemovingWhitespaceHelped = false; 80 if (ArgLower == "[in]") { 81 Direction = ParamCommandComment::In; 82 RemovingWhitespaceHelped = true; 83 } else if (ArgLower == "[out]") { 84 Direction = ParamCommandComment::Out; 85 RemovingWhitespaceHelped = true; 86 } else if (ArgLower == "[in,out]" || ArgLower == "[out,in]") { 87 Direction = ParamCommandComment::InOut; 88 RemovingWhitespaceHelped = true; 89 } else { 90 Direction = ParamCommandComment::In; 91 RemovingWhitespaceHelped = false; 92 } 93 // Diag() unrecognized parameter passing direction, valid directions are ... 94 // if (RemovingWhitespaceHelped) FixIt 95 } 96 Command->setDirection(Direction, /* Explicit = */ true); 97 } else { 98 if (Command->getArgCount() == 0) { 99 if (!Command->isDirectionExplicit()) { 100 // User didn't provide a direction argument. 101 Command->setDirection(ParamCommandComment::In, /* Explicit = */ false); 102 } 103 typedef BlockCommandComment::Argument Argument; 104 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 105 ArgLocEnd), 106 Arg); 107 Command->setArgs(llvm::makeArrayRef(A, 1)); 108 // if (...) Diag() unrecognized parameter name 109 } else { 110 // Diag() \\param command requires at most 2 arguments 111 } 112 } 113 return Command; 114 } 115 116 ParamCommandComment *Sema::actOnParamCommandFinish(ParamCommandComment *Command, 117 ParagraphComment *Paragraph) { 118 Command->setParagraph(Paragraph); 119 return Command; 120 } 121 122 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, 123 SourceLocation CommandLocEnd, 124 StringRef CommandName) { 125 ArrayRef<InlineCommandComment::Argument> Args; 126 return new (Allocator) InlineCommandComment(CommandLocBegin, 127 CommandLocEnd, 128 CommandName, 129 Args); 130 } 131 132 InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin, 133 SourceLocation CommandLocEnd, 134 StringRef CommandName, 135 SourceLocation ArgLocBegin, 136 SourceLocation ArgLocEnd, 137 StringRef Arg) { 138 typedef InlineCommandComment::Argument Argument; 139 Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin, 140 ArgLocEnd), 141 Arg); 142 143 return new (Allocator) InlineCommandComment(CommandLocBegin, 144 CommandLocEnd, 145 CommandName, 146 llvm::makeArrayRef(A, 1)); 147 } 148 149 InlineContentComment *Sema::actOnUnknownCommand(SourceLocation LocBegin, 150 SourceLocation LocEnd, 151 StringRef Name) { 152 ArrayRef<InlineCommandComment::Argument> Args; 153 return new (Allocator) InlineCommandComment(LocBegin, LocEnd, Name, Args); 154 } 155 156 TextComment *Sema::actOnText(SourceLocation LocBegin, 157 SourceLocation LocEnd, 158 StringRef Text) { 159 return new (Allocator) TextComment(LocBegin, LocEnd, Text); 160 } 161 162 VerbatimBlockComment *Sema::actOnVerbatimBlockStart(SourceLocation Loc, 163 StringRef Name) { 164 return new (Allocator) VerbatimBlockComment( 165 Loc, 166 Loc.getLocWithOffset(1 + Name.size()), 167 Name); 168 } 169 170 VerbatimBlockLineComment *Sema::actOnVerbatimBlockLine(SourceLocation Loc, 171 StringRef Text) { 172 return new (Allocator) VerbatimBlockLineComment(Loc, Text); 173 } 174 175 VerbatimBlockComment *Sema::actOnVerbatimBlockFinish( 176 VerbatimBlockComment *Block, 177 SourceLocation CloseNameLocBegin, 178 StringRef CloseName, 179 ArrayRef<VerbatimBlockLineComment *> Lines) { 180 Block->setCloseName(CloseName, CloseNameLocBegin); 181 Block->setLines(Lines); 182 return Block; 183 } 184 185 VerbatimLineComment *Sema::actOnVerbatimLine(SourceLocation LocBegin, 186 StringRef Name, 187 SourceLocation TextBegin, 188 StringRef Text) { 189 return new (Allocator) VerbatimLineComment( 190 LocBegin, 191 TextBegin.getLocWithOffset(Text.size()), 192 Name, 193 TextBegin, 194 Text); 195 } 196 197 HTMLOpenTagComment *Sema::actOnHTMLOpenTagStart(SourceLocation LocBegin, 198 StringRef TagName) { 199 return new (Allocator) HTMLOpenTagComment(LocBegin, TagName); 200 } 201 202 HTMLOpenTagComment *Sema::actOnHTMLOpenTagFinish( 203 HTMLOpenTagComment *Tag, 204 ArrayRef<HTMLOpenTagComment::Attribute> Attrs, 205 SourceLocation GreaterLoc) { 206 Tag->setAttrs(Attrs); 207 Tag->setGreaterLoc(GreaterLoc); 208 return Tag; 209 } 210 211 HTMLCloseTagComment *Sema::actOnHTMLCloseTag(SourceLocation LocBegin, 212 SourceLocation LocEnd, 213 StringRef TagName) { 214 return new (Allocator) HTMLCloseTagComment(LocBegin, LocEnd, TagName); 215 } 216 217 FullComment *Sema::actOnFullComment( 218 ArrayRef<BlockContentComment *> Blocks) { 219 return new (Allocator) FullComment(Blocks); 220 } 221 222 // TODO: tablegen 223 bool Sema::isBlockCommand(StringRef Name) { 224 return llvm::StringSwitch<bool>(Name) 225 .Case("brief", true) 226 .Case("result", true) 227 .Case("return", true) 228 .Case("returns", true) 229 .Case("author", true) 230 .Case("authors", true) 231 .Case("pre", true) 232 .Case("post", true) 233 .Default(false) || isParamCommand(Name); 234 } 235 236 bool Sema::isParamCommand(StringRef Name) { 237 return llvm::StringSwitch<bool>(Name) 238 .Case("param", true) 239 .Case("arg", true) 240 .Default(false); 241 } 242 243 unsigned Sema::getBlockCommandNumArgs(StringRef Name) { 244 return llvm::StringSwitch<unsigned>(Name) 245 .Case("brief", 0) 246 .Case("pre", 0) 247 .Case("post", 0) 248 .Case("author", 0) 249 .Case("authors", 0) 250 .Default(0); 251 } 252 253 bool Sema::isInlineCommand(StringRef Name) { 254 return llvm::StringSwitch<bool>(Name) 255 .Case("c", true) 256 .Case("em", true) 257 .Default(false); 258 } 259 260 bool Sema::HTMLOpenTagNeedsClosing(StringRef Name) { 261 return llvm::StringSwitch<bool>(Name) 262 .Case("br", true) 263 .Default(true); 264 } 265 266 } // end namespace comments 267 } // end namespace clang 268 269