ObjCAtCatchStmt::ObjCAtCatchStmt(SourceLocation atCatchLoc, SourceLocation rparenloc, ParmVarDecl *catchVarDecl, Stmt *atCatchStmt, Stmt *atCatchList) : Stmt(ObjCAtCatchStmtClass) { ExceptionDecl = catchVarDecl; SubExprs[BODY] = atCatchStmt; SubExprs[NEXT_CATCH] = NULL; // FIXME: O(N^2) in number of catch blocks. if (atCatchList) { ObjCAtCatchStmt *AtCatchList = static_cast<ObjCAtCatchStmt*>(atCatchList); while (ObjCAtCatchStmt* NextCatch = AtCatchList->getNextCatchStmt()) AtCatchList = NextCatch; AtCatchList->SubExprs[NEXT_CATCH] = this; } AtCatchLoc = atCatchLoc; RParenLoc = rparenloc; }
/// BuildScopeInformation - The statements from CI to CE are known to form a /// coherent VLA scope with a specified parent node. Walk through the /// statements, adding any labels or gotos to LabelAndGotoScopes and recursively /// walking the AST as needed. void JumpScopeChecker::BuildScopeInformation(Stmt *S, unsigned ParentScope) { // If we found a label, remember that it is in ParentScope scope. if (isa<LabelStmt>(S) || isa<DefaultStmt>(S) || isa<CaseStmt>(S)) { LabelAndGotoScopes[S] = ParentScope; } else if (isa<GotoStmt>(S) || isa<SwitchStmt>(S) || isa<IndirectGotoStmt>(S) || isa<AddrLabelExpr>(S)) { // Remember both what scope a goto is in as well as the fact that we have // it. This makes the second scan not have to walk the AST again. LabelAndGotoScopes[S] = ParentScope; Jumps.push_back(S); } for (Stmt::child_iterator CI = S->child_begin(), E = S->child_end(); CI != E; ++CI) { Stmt *SubStmt = *CI; if (SubStmt == 0) continue; bool isCPlusPlus = this->S.getLangOptions().CPlusPlus; // If this is a declstmt with a VLA definition, it defines a scope from here // to the end of the containing context. if (DeclStmt *DS = dyn_cast<DeclStmt>(SubStmt)) { // The decl statement creates a scope if any of the decls in it are VLAs // or have the cleanup attribute. for (DeclStmt::decl_iterator I = DS->decl_begin(), E = DS->decl_end(); I != E; ++I) { // If this decl causes a new scope, push and switch to it. if (unsigned Diag = GetDiagForGotoScopeDecl(*I, isCPlusPlus)) { Scopes.push_back(GotoScope(ParentScope, Diag, (*I)->getLocation())); ParentScope = Scopes.size()-1; } // If the decl has an initializer, walk it with the potentially new // scope we just installed. if (VarDecl *VD = dyn_cast<VarDecl>(*I)) if (Expr *Init = VD->getInit()) BuildScopeInformation(Init, ParentScope); } continue; } // Disallow jumps into any part of an @try statement by pushing a scope and // walking all sub-stmts in that scope. if (ObjCAtTryStmt *AT = dyn_cast<ObjCAtTryStmt>(SubStmt)) { // Recursively walk the AST for the @try part. Scopes.push_back(GotoScope(ParentScope,diag::note_protected_by_objc_try, AT->getAtTryLoc())); if (Stmt *TryPart = AT->getTryBody()) BuildScopeInformation(TryPart, Scopes.size()-1); // Jump from the catch to the finally or try is not valid. for (ObjCAtCatchStmt *AC = AT->getCatchStmts(); AC; AC = AC->getNextCatchStmt()) { Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_catch, AC->getAtCatchLoc())); // @catches are nested and it isn't BuildScopeInformation(AC->getCatchBody(), Scopes.size()-1); } // Jump from the finally to the try or catch is not valid. if (ObjCAtFinallyStmt *AF = AT->getFinallyStmt()) { Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_finally, AF->getAtFinallyLoc())); BuildScopeInformation(AF, Scopes.size()-1); } continue; } // Disallow jumps into the protected statement of an @synchronized, but // allow jumps into the object expression it protects. if (ObjCAtSynchronizedStmt *AS = dyn_cast<ObjCAtSynchronizedStmt>(SubStmt)){ // Recursively walk the AST for the @synchronized object expr, it is // evaluated in the normal scope. BuildScopeInformation(AS->getSynchExpr(), ParentScope); // Recursively walk the AST for the @synchronized part, protected by a new // scope. Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_objc_synchronized, AS->getAtSynchronizedLoc())); BuildScopeInformation(AS->getSynchBody(), Scopes.size()-1); continue; } // Disallow jumps into any part of a C++ try statement. This is pretty // much the same as for Obj-C. if (CXXTryStmt *TS = dyn_cast<CXXTryStmt>(SubStmt)) { Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_try, TS->getSourceRange().getBegin())); if (Stmt *TryBlock = TS->getTryBlock()) BuildScopeInformation(TryBlock, Scopes.size()-1); // Jump from the catch into the try is not allowed either. for (unsigned I = 0, E = TS->getNumHandlers(); I != E; ++I) { CXXCatchStmt *CS = TS->getHandler(I); Scopes.push_back(GotoScope(ParentScope, diag::note_protected_by_cxx_catch, CS->getSourceRange().getBegin())); BuildScopeInformation(CS->getHandlerBlock(), Scopes.size()-1); } continue; } // Recursively walk the AST. BuildScopeInformation(SubStmt, ParentScope); } }