 |
|
 |
|
| Files: |
1 |
|
Branches Taken: |
79.3% |
88 / 111 |
| Generated: |
2010-02-10 01:31 |
|
Branches Executed: |
89.2% |
99 / 111 |
| |
|
Line Coverage: |
88.5% |
123 / 139 |
| |
 |
|
 |
1 : //===--- ParseCXXInlineMethods.cpp - C++ class inline methods parsing------===//
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 : // This file implements parsing for C++ class inline methods.
11 : //
12 : //===----------------------------------------------------------------------===//
13 :
14 : #include "clang/Parse/ParseDiagnostic.h"
15 : #include "clang/Parse/Parser.h"
16 : #include "clang/Parse/DeclSpec.h"
17 : #include "clang/Parse/Scope.h"
18 : using namespace clang;
19 :
20 : /// ParseCXXInlineMethodDef - We parsed and verified that the specified
21 : /// Declarator is a well formed C++ inline method definition. Now lex its body
22 : /// and store its tokens for parsing after the C++ class is complete.
23 : Parser::DeclPtrTy
24 : Parser::ParseCXXInlineMethodDef(AccessSpecifier AS, Declarator &D,
25 1051: const ParsedTemplateInfo &TemplateInfo) {
26 : assert(D.getTypeObject(0).Kind == DeclaratorChunk::Function &&
1051: branch 1 taken
0: branch 2 not taken
27 1051: "This isn't a function declarator!");
28 : assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try)) &&
162: branch 1 taken
889: branch 2 taken
3: branch 4 taken
159: branch 5 taken
3: branch 7 taken
0: branch 8 not taken
29 1213: "Current token not a '{', ':' or 'try'!");
30 :
31 : Action::MultiTemplateParamsArg TemplateParams(Actions,
32 : TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->data() : 0,
42: branch 0 taken
1009: branch 1 taken
42: branch 3 taken
1009: branch 4 taken
33 1093: TemplateInfo.TemplateParams? TemplateInfo.TemplateParams->size() : 0);
34 1051: DeclPtrTy FnD;
3: branch 2 taken
1048: branch 3 taken
35 1051: if (D.getDeclSpec().isFriendSpecified())
36 : // FIXME: Friend templates
37 3: FnD = Actions.ActOnFriendFunctionDecl(CurScope, D, true, move(TemplateParams));
38 : else // FIXME: pass template information through
39 : FnD = Actions.ActOnCXXMemberDeclarator(CurScope, AS, D,
40 : move(TemplateParams), 0, 0,
41 1048: /*IsDefinition*/true);
42 :
43 1051: HandleMemberFunctionDefaultArgs(D, FnD);
44 :
45 : // Consume the tokens and store them for later parsing.
46 :
47 1051: getCurrentClass().MethodDefs.push_back(LexedMethod(FnD));
48 : getCurrentClass().MethodDefs.back().TemplateScope
49 1051: = CurScope->isTemplateParamScope();
50 1051: CachedTokens &Toks = getCurrentClass().MethodDefs.back().Toks;
51 :
52 1051: tok::TokenKind kind = Tok.getKind();
53 : // We may have a constructor initializer or function-try-block here.
892: branch 0 taken
159: branch 1 taken
3: branch 2 taken
889: branch 3 taken
54 1210: if (kind == tok::colon || kind == tok::kw_try) {
55 : // Consume everything up to (and including) the left brace.
3: branch 1 taken
159: branch 2 taken
56 162: if (!ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks, tok::semi)) {
57 : // We didn't find the left-brace we expected after the
58 : // constructor initializer.
3: branch 1 taken
0: branch 2 not taken
59 3: if (Tok.is(tok::semi)) {
60 : // We found a semicolon; complain, consume the semicolon, and
61 : // don't try to parse this method later.
62 3: Diag(Tok.getLocation(), diag::err_expected_lbrace);
63 3: ConsumeAnyToken();
64 3: getCurrentClass().MethodDefs.pop_back();
65 3: return FnD;
66 : }
67 : }
68 :
69 : } else {
70 : // Begin by storing the '{' token.
71 889: Toks.push_back(Tok);
72 889: ConsumeBrace();
73 : }
74 : // Consume everything up to (and including) the matching right brace.
75 1048: ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
76 :
77 : // If we're in a function-try-block, we need to store all the catch blocks.
3: branch 0 taken
1045: branch 1 taken
78 1048: if (kind == tok::kw_try) {
3: branch 1 taken
3: branch 2 taken
79 9: while (Tok.is(tok::kw_catch)) {
80 3: ConsumeAndStoreUntil(tok::l_brace, tok::unknown, Toks);
81 3: ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
82 : }
83 : }
84 :
85 1048: return FnD;
86 : }
87 :
88 : /// ParseLexedMethodDeclarations - We finished parsing the member
89 : /// specification of a top (non-nested) C++ class. Now go over the
90 : /// stack of method declarations with some parts for which parsing was
91 : /// delayed (such as default arguments) and parse them.
92 3199: void Parser::ParseLexedMethodDeclarations(ParsingClass &Class) {
25: branch 0 taken
3174: branch 1 taken
11: branch 2 taken
14: branch 3 taken
93 3199: bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
94 3199: ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
11: branch 0 taken
3188: branch 1 taken
95 3199: if (HasTemplateScope)
96 11: Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
97 :
98 : // The current scope is still active if we're the top-level class.
99 : // Otherwise we'll need to push and enter a new scope.
100 3199: bool HasClassScope = !Class.TopLevelClass;
101 3199: ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope, HasClassScope);
25: branch 0 taken
3174: branch 1 taken
102 3199: if (HasClassScope)
103 25: Actions.ActOnStartDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
104 :
68: branch 4 taken
3199: branch 5 taken
105 3267: for (; !Class.MethodDecls.empty(); Class.MethodDecls.pop_front()) {
106 68: LateParsedMethodDeclaration &LM = Class.MethodDecls.front();
107 :
108 : // If this is a member template, introduce the template parameter scope.
109 68: ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
3: branch 0 taken
65: branch 1 taken
110 68: if (LM.TemplateScope)
111 3: Actions.ActOnReenterTemplateScope(CurScope, LM.Method);
112 :
113 : // Start the delayed C++ method declaration
114 68: Actions.ActOnStartDelayedCXXMethodDeclaration(CurScope, LM.Method);
115 :
116 : // Introduce the parameters into scope and parse their default
117 : // arguments.
118 : ParseScope PrototypeScope(this,
119 68: Scope::FunctionPrototypeScope|Scope::DeclScope);
107: branch 1 taken
68: branch 2 taken
120 175: for (unsigned I = 0, N = LM.DefaultArgs.size(); I != N; ++I) {
121 : // Introduce the parameter into scope.
122 107: Actions.ActOnDelayedCXXMethodParameter(CurScope, LM.DefaultArgs[I].Param);
123 :
81: branch 1 taken
26: branch 2 taken
124 107: if (CachedTokens *Toks = LM.DefaultArgs[I].Toks) {
125 : // Parse the default argument from its saved token stream.
126 81: Toks->push_back(Tok); // So that the current token doesn't get lost
127 81: PP.EnterTokenStream(&Toks->front(), Toks->size(), true, false);
128 :
129 : // Consume the previously-pushed token.
130 81: ConsumeAnyToken();
131 :
132 : // Consume the '='.
81: branch 1 taken
0: branch 2 not taken
133 81: assert(Tok.is(tok::equal) && "Default argument not starting with '='");
134 81: SourceLocation EqualLoc = ConsumeToken();
135 :
136 81: OwningExprResult DefArgResult(ParseAssignmentExpression());
5: branch 1 taken
76: branch 2 taken
137 81: if (DefArgResult.isInvalid())
138 5: Actions.ActOnParamDefaultArgumentError(LM.DefaultArgs[I].Param);
139 : else
140 : Actions.ActOnParamDefaultArgument(LM.DefaultArgs[I].Param, EqualLoc,
141 76: move(DefArgResult));
81: branch 0 taken
0: branch 1 not taken
142 81: delete Toks;
143 81: LM.DefaultArgs[I].Toks = 0;
144 : }
145 : }
146 68: PrototypeScope.Exit();
147 :
148 : // Finish the delayed C++ method declaration.
149 68: Actions.ActOnFinishDelayedCXXMethodDeclaration(CurScope, LM.Method);
150 : }
151 :
25: branch 1 taken
3199: branch 2 taken
152 3224: for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
153 25: ParseLexedMethodDeclarations(*Class.NestedClasses[I]);
154 :
25: branch 0 taken
3174: branch 1 taken
155 3199: if (HasClassScope)
156 25: Actions.ActOnFinishDelayedMemberDeclarations(CurScope, Class.TagOrTemplate);
157 3199: }
158 :
159 : /// ParseLexedMethodDefs - We finished parsing the member specification of a top
160 : /// (non-nested) C++ class. Now go over the stack of lexed methods that were
161 : /// collected during its parsing and parse them all.
162 3199: void Parser::ParseLexedMethodDefs(ParsingClass &Class) {
25: branch 0 taken
3174: branch 1 taken
11: branch 2 taken
14: branch 3 taken
163 3199: bool HasTemplateScope = !Class.TopLevelClass && Class.TemplateScope;
164 3199: ParseScope TemplateScope(this, Scope::TemplateParamScope, HasTemplateScope);
11: branch 0 taken
3188: branch 1 taken
165 3199: if (HasTemplateScope)
166 11: Actions.ActOnReenterTemplateScope(CurScope, Class.TagOrTemplate);
167 :
168 3199: bool HasClassScope = !Class.TopLevelClass;
169 : ParseScope ClassScope(this, Scope::ClassScope|Scope::DeclScope,
170 3199: HasClassScope);
171 :
1045: branch 1 taken
3: branch 2 taken
1045: branch 4 taken
3: branch 5 taken
1048: branch 8 taken
3199: branch 9 taken
172 5295: for (; !Class.MethodDefs.empty(); Class.MethodDefs.pop_front()) {
173 1048: LexedMethod &LM = Class.MethodDefs.front();
174 :
175 : // If this is a member template, introduce the template parameter scope.
176 1048: ParseScope TemplateScope(this, Scope::TemplateParamScope, LM.TemplateScope);
42: branch 0 taken
1006: branch 1 taken
177 1048: if (LM.TemplateScope)
178 42: Actions.ActOnReenterTemplateScope(CurScope, LM.D);
179 :
1048: branch 1 taken
0: branch 2 not taken
180 1048: assert(!LM.Toks.empty() && "Empty body!");
181 : // Append the current token at the end of the new token stream so that it
182 : // doesn't get lost.
183 1048: LM.Toks.push_back(Tok);
184 1048: PP.EnterTokenStream(LM.Toks.data(), LM.Toks.size(), true, false);
185 :
186 : // Consume the previously pushed token.
187 1048: ConsumeAnyToken();
188 : assert((Tok.is(tok::l_brace) || Tok.is(tok::colon) || Tok.is(tok::kw_try))
159: branch 1 taken
889: branch 2 taken
3: branch 4 taken
156: branch 5 taken
3: branch 7 taken
0: branch 8 not taken
189 1207: && "Inline method not starting with '{', ':' or 'try'");
190 :
191 : // Parse the method body. Function body parsing code is similar enough
192 : // to be re-used for method bodies as well.
193 1048: ParseScope FnScope(this, Scope::FnScope|Scope::DeclScope);
194 1048: Actions.ActOnStartOfFunctionDef(CurScope, LM.D);
195 :
3: branch 1 taken
1045: branch 2 taken
196 1048: if (Tok.is(tok::kw_try)) {
197 3: ParseFunctionTryBlock(LM.D);
198 3: continue;
199 : }
156: branch 1 taken
889: branch 2 taken
200 1045: if (Tok.is(tok::colon))
201 156: ParseConstructorInitializer(LM.D);
202 : else
203 889: Actions.ActOnDefaultCtorInitializers(LM.D);
204 :
205 : // FIXME: What if ParseConstructorInitializer doesn't leave us with a '{'??
206 1045: ParseFunctionStatementBody(LM.D);
207 : }
208 :
25: branch 1 taken
3199: branch 2 taken
209 3224: for (unsigned I = 0, N = Class.NestedClasses.size(); I != N; ++I)
210 3224: ParseLexedMethodDefs(*Class.NestedClasses[I]);
211 3199: }
212 :
213 : /// ConsumeAndStoreUntil - Consume and store the token at the passed token
214 : /// container until the token 'T' is reached (which gets
215 : /// consumed/stored too, if ConsumeFinalToken).
216 : /// If EarlyAbortIf is specified, then we will stop early if we find that
217 : /// token at the top level.
218 : /// Returns true if token 'T1' or 'T2' was found.
219 : /// NOTE: This is a specialized version of Parser::SkipUntil.
220 : bool Parser::ConsumeAndStoreUntil(tok::TokenKind T1, tok::TokenKind T2,
221 : CachedTokens &Toks,
222 : tok::TokenKind EarlyAbortIf,
223 2460: bool ConsumeFinalToken) {
224 : // We always want this function to consume at least one token if the first
225 : // token isn't T and if not at EOF.
226 2460: bool isFirstTokenConsumed = true;
227 8007: while (1) {
228 : // If we found one of the tokens, stop and return true.
8078: branch 1 taken
2389: branch 2 taken
68: branch 4 taken
8010: branch 5 taken
2457: branch 6 taken
8010: branch 7 taken
229 10467: if (Tok.is(T1) || Tok.is(T2)) {
2375: branch 0 taken
82: branch 1 taken
230 2457: if (ConsumeFinalToken) {
231 2375: Toks.push_back(Tok);
232 2375: ConsumeAnyToken();
233 : }
234 2457: return true;
235 : }
236 :
237 : // If we found the early-abort token, return.
3: branch 1 taken
8007: branch 2 taken
238 8010: if (Tok.is(EarlyAbortIf))
239 3: return false;
240 :
0: branch 1 not taken
1016: branch 2 taken
67: branch 3 taken
44: branch 4 taken
0: branch 5 not taken
0: branch 6 not taken
0: branch 7 not taken
220: branch 8 taken
6660: branch 9 taken
241 8007: switch (Tok.getKind()) {
242 : case tok::eof:
243 : // Ran out of tokens.
244 0: return false;
245 :
246 : case tok::l_paren:
247 : // Recursively consume properly-nested parens.
248 1016: Toks.push_back(Tok);
249 1016: ConsumeParen();
250 1016: ConsumeAndStoreUntil(tok::r_paren, tok::unknown, Toks);
251 1016: break;
252 : case tok::l_square:
253 : // Recursively consume properly-nested square brackets.
254 67: Toks.push_back(Tok);
255 67: ConsumeBracket();
256 67: ConsumeAndStoreUntil(tok::r_square, tok::unknown, Toks);
257 67: break;
258 : case tok::l_brace:
259 : // Recursively consume properly-nested braces.
260 44: Toks.push_back(Tok);
261 44: ConsumeBrace();
262 44: ConsumeAndStoreUntil(tok::r_brace, tok::unknown, Toks);
263 44: break;
264 :
265 : // Okay, we found a ']' or '}' or ')', which we think should be balanced.
266 : // Since the user wasn't looking for this token (if they were, it would
267 : // already be handled), this isn't balanced. If there is a LHS token at a
268 : // higher level, we will assume that this matches the unbalanced token
269 : // and return it. Otherwise, this is a spurious RHS token, which we skip.
270 : case tok::r_paren:
0: branch 0 not taken
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
271 0: if (ParenCount && !isFirstTokenConsumed)
272 0: return false; // Matches something.
273 0: Toks.push_back(Tok);
274 0: ConsumeParen();
275 0: break;
276 : case tok::r_square:
0: branch 0 not taken
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
277 0: if (BracketCount && !isFirstTokenConsumed)
278 0: return false; // Matches something.
279 0: Toks.push_back(Tok);
280 0: ConsumeBracket();
281 0: break;
282 : case tok::r_brace:
0: branch 0 not taken
0: branch 1 not taken
0: branch 2 not taken
0: branch 3 not taken
283 0: if (BraceCount && !isFirstTokenConsumed)
284 0: return false; // Matches something.
285 0: Toks.push_back(Tok);
286 0: ConsumeBrace();
287 0: break;
288 :
289 : case tok::string_literal:
290 : case tok::wide_string_literal:
291 220: Toks.push_back(Tok);
292 220: ConsumeStringToken();
293 220: break;
294 : default:
295 : // consume this token.
296 6660: Toks.push_back(Tok);
297 6660: ConsumeToken();
298 : break;
299 : }
300 8007: isFirstTokenConsumed = false;
301 : }
302 : }
Generated: 2010-02-10 01:31 by zcov