zcov: / lib/Parse/ParseCXXInlineMethods.cpp


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


Programs: 2 Runs 3018


       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