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