diff options
-rw-r--r-- | include/clang/AST/ExprCXX.h | 5 | ||||
-rw-r--r-- | include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h | 22 | ||||
-rw-r--r-- | lib/AST/ExprCXX.cpp | 15 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/AggExprVisitor.cpp | 2 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CFRefCount.cpp | 31 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/CXXExprEngine.cpp | 111 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 159 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ObjCMessage.cpp | 20 | ||||
-rw-r--r-- | test/Analysis/base-init.cpp | 1 | ||||
-rw-r--r-- | test/Analysis/inline.c | 1 | ||||
-rw-r--r-- | test/Analysis/misc-ps-region-store.cpp | 16 |
11 files changed, 202 insertions, 181 deletions
diff --git a/include/clang/AST/ExprCXX.h b/include/clang/AST/ExprCXX.h index 30481ba779..e926267f5c 100644 --- a/include/clang/AST/ExprCXX.h +++ b/include/clang/AST/ExprCXX.h @@ -99,7 +99,10 @@ public: /// getImplicitObjectArgument - Retrieves the implicit object /// argument for the member call. For example, in "x.f(5)", this /// operation would return "x". - Expr *getImplicitObjectArgument(); + Expr *getImplicitObjectArgument() const; + + /// Retrieves the declaration of the called method. + CXXMethodDecl *getMethodDecl() const; /// getRecordDecl - Retrieves the CXXRecordDecl for the underlying type of /// the implicit object argument. Note that this is may not be the same diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h index 7a562482c2..3708bb8e11 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h @@ -264,10 +264,8 @@ public: /// VisitCall - Transfer function for function calls. - void VisitCall(const CallExpr* CE, ExplodedNode* Pred, - CallExpr::const_arg_iterator AI, - CallExpr::const_arg_iterator AE, - ExplodedNodeSet& Dst); + void VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred, + ExplodedNodeSet& Dst); /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, @@ -362,12 +360,6 @@ public: const MemRegion *Dest, const Stmt *S, ExplodedNode *Pred, ExplodedNodeSet &Dst); - void VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, ExplodedNode *Pred, - ExplodedNodeSet &Dst); - - void VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C, - ExplodedNode *Pred, ExplodedNodeSet &Dst); - void VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst); @@ -393,12 +385,10 @@ public: const FunctionProtoType *FnType, ExplodedNode *Pred, ExplodedNodeSet &Dst, bool FstArgAsLValue = false); - - /// Evaluate method call itself. Used for CXXMethodCallExpr and - /// CXXOperatorCallExpr. - void evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, - const Expr *ThisExpr, ExplodedNode *Pred, - ExplodedNodeSet &Src, ExplodedNodeSet &Dst); + + /// Evaluate callee expression (for a function call). + void evalCallee(const CallExpr *callExpr, const ExplodedNodeSet &src, + ExplodedNodeSet &dest); /// evalEagerlyAssume - Given the nodes in 'Src', eagerly assume symbolic /// expressions of the form 'x != 0' and generate new nodes (stored in Dst) diff --git a/lib/AST/ExprCXX.cpp b/lib/AST/ExprCXX.cpp index 35c2d41008..02d60ef0a7 100644 --- a/lib/AST/ExprCXX.cpp +++ b/lib/AST/ExprCXX.cpp @@ -384,14 +384,25 @@ SourceRange CXXOperatorCallExpr::getSourceRange() const { } } -Expr *CXXMemberCallExpr::getImplicitObjectArgument() { - if (MemberExpr *MemExpr = dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) +Expr *CXXMemberCallExpr::getImplicitObjectArgument() const { + if (const MemberExpr *MemExpr = + dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) return MemExpr->getBase(); // FIXME: Will eventually need to cope with member pointers. return 0; } +CXXMethodDecl *CXXMemberCallExpr::getMethodDecl() const { + if (const MemberExpr *MemExpr = + dyn_cast<MemberExpr>(getCallee()->IgnoreParens())) + return cast<CXXMethodDecl>(MemExpr->getMemberDecl()); + + // FIXME: Will eventually need to cope with member pointers. + return 0; +} + + CXXRecordDecl *CXXMemberCallExpr::getRecordDecl() { Expr* ThisArg = getImplicitObjectArgument(); if (!ThisArg) diff --git a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp index e80cf9b4a3..901190d901 100644 --- a/lib/StaticAnalyzer/Core/AggExprVisitor.cpp +++ b/lib/StaticAnalyzer/Core/AggExprVisitor.cpp @@ -60,7 +60,7 @@ void AggExprVisitor::VisitCXXConstructExpr(CXXConstructExpr *E) { } void AggExprVisitor::VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { - Eng.VisitCXXMemberCallExpr(E, Pred, DstSet); + Eng.Visit(E, Pred, DstSet); } void ExprEngine::VisitAggExpr(const Expr *E, const MemRegion *Dest, diff --git a/lib/StaticAnalyzer/Core/CFRefCount.cpp b/lib/StaticAnalyzer/Core/CFRefCount.cpp index 690ffb5876..416e1209ae 100644 --- a/lib/StaticAnalyzer/Core/CFRefCount.cpp +++ b/lib/StaticAnalyzer/Core/CFRefCount.cpp @@ -16,6 +16,7 @@ #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclCXX.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/LangOptions.h" #include "clang/Basic/SourceManager.h" @@ -2680,11 +2681,14 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, // FIXME: We eventually should handle structs and other compound types // that are returned by value. - QualType T = callOrMsg.getResultType(Eng.getContext()); - if (Loc::isLocType(T) || (T->isIntegerType() && T->isScalarType())) { + // Use the result type from callOrMsg as it automatically adjusts + // for methods/functions that return references. + QualType resultTy = callOrMsg.getResultType(Eng.getContext()); + if (Loc::isLocType(resultTy) || + (resultTy->isIntegerType() && resultTy->isScalarType())) { unsigned Count = Builder.getCurrentBlockCount(); SValBuilder &svalBuilder = Eng.getSValBuilder(); - SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, T, Count); + SVal X = svalBuilder.getConjuredSymbolVal(NULL, Ex, resultTy, Count); state = state->BindExpr(Ex, X, false); } @@ -2711,9 +2715,12 @@ void CFRefCount::evalSummary(ExplodedNodeSet& Dst, unsigned Count = Builder.getCurrentBlockCount(); SValBuilder &svalBuilder = Eng.getSValBuilder(); SymbolRef Sym = svalBuilder.getConjuredSymbol(Ex, Count); - QualType RetT = GetReturnType(Ex, svalBuilder.getContext()); + + // Use the result type from callOrMsg as it automatically adjusts + // for methods/functions that return references. + QualType resultTy = callOrMsg.getResultType(Eng.getContext()); state = state->set<RefBindings>(Sym, RefVal::makeOwned(RE.getObjKind(), - RetT)); + resultTy)); state = state->BindExpr(Ex, svalBuilder.makeLoc(Sym), false); // FIXME: Add a flag to the checker where allocations are assumed to @@ -2766,11 +2773,17 @@ void CFRefCount::evalCall(ExplodedNodeSet& Dst, if (dyn_cast_or_null<BlockDataRegion>(L.getAsRegion())) { Summ = Summaries.getPersistentStopSummary(); } - else { - const FunctionDecl* FD = L.getAsFunctionDecl(); - Summ = !FD ? Summaries.getDefaultSummary() : - Summaries.getSummary(FD); + else if (const FunctionDecl* FD = L.getAsFunctionDecl()) { + Summ = Summaries.getSummary(FD); } + else if (const CXXMemberCallExpr *me = dyn_cast<CXXMemberCallExpr>(CE)) { + if (const CXXMethodDecl *MD = me->getMethodDecl()) + Summ = Summaries.getSummary(MD); + else + Summ = Summaries.getDefaultSummary(); + } + else + Summ = Summaries.getDefaultSummary(); assert(Summ); evalSummary(Dst, Eng, Builder, CE, diff --git a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp index a71761dab8..b015d4f264 100644 --- a/lib/StaticAnalyzer/Core/CXXExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/CXXExprEngine.cpp @@ -62,6 +62,34 @@ void ExprEngine::evalArguments(ConstExprIterator AI, ConstExprIterator AE, } } +void ExprEngine::evalCallee(const CallExpr *callExpr, + const ExplodedNodeSet &src, + ExplodedNodeSet &dest) { + + const Expr *callee = 0; + + switch (callExpr->getStmtClass()) { + case Stmt::CXXMemberCallExprClass: { + // Evaluate the implicit object argument that is the recipient of the + // call. + callee = cast<CXXMemberCallExpr>(callExpr)->getImplicitObjectArgument(); + + // FIXME: handle member pointers. + if (!callee) + return; + + break; + } + default: { + callee = callExpr->getCallee()->IgnoreParens(); + break; + } + } + + for (ExplodedNodeSet::iterator i = src.begin(), e = src.end(); i != e; ++i) + Visit(callee, *i, dest); +} + const CXXThisRegion *ExprEngine::getCXXThisRegion(const CXXRecordDecl *D, const StackFrameContext *SFC) { const Type *T = D->getTypeForDecl(); @@ -169,89 +197,6 @@ void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD, Dst.Add(N); } -void ExprEngine::VisitCXXMemberCallExpr(const CXXMemberCallExpr *MCE, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - // Get the method type. - const FunctionProtoType *FnType = - MCE->getCallee()->getType()->getAs<FunctionProtoType>(); - assert(FnType && "Method type not available"); - - // Evaluate explicit arguments with a worklist. - ExplodedNodeSet argsEvaluated; - evalArguments(MCE->arg_begin(), MCE->arg_end(), FnType, Pred, argsEvaluated); - - // Evaluate the implicit object argument. - ExplodedNodeSet AllargsEvaluated; - const MemberExpr *ME = dyn_cast<MemberExpr>(MCE->getCallee()->IgnoreParens()); - if (!ME) - return; - Expr *ObjArgExpr = ME->getBase(); - for (ExplodedNodeSet::iterator I = argsEvaluated.begin(), - E = argsEvaluated.end(); I != E; ++I) { - Visit(ObjArgExpr, *I, AllargsEvaluated); - } - - // Now evaluate the call itself. - const CXXMethodDecl *MD = cast<CXXMethodDecl>(ME->getMemberDecl()); - assert(MD && "not a CXXMethodDecl?"); - evalMethodCall(MCE, MD, ObjArgExpr, Pred, AllargsEvaluated, Dst); -} - -void ExprEngine::VisitCXXOperatorCallExpr(const CXXOperatorCallExpr *C, - ExplodedNode *Pred, - ExplodedNodeSet &Dst) { - const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(C->getCalleeDecl()); - if (!MD) { - // If the operator doesn't represent a method call treat as regular call. - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); - return; - } - - // Determine the type of function we're calling (if available). - const FunctionProtoType *Proto = NULL; - QualType FnType = C->getCallee()->IgnoreParens()->getType(); - if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) - Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>(); - - // Evaluate arguments treating the first one (object method is called on) - // as alvalue. - ExplodedNodeSet argsEvaluated; - evalArguments(C->arg_begin(), C->arg_end(), Proto, Pred, argsEvaluated, true); - - // Now evaluate the call itself. - evalMethodCall(C, MD, C->getArg(0), Pred, argsEvaluated, Dst); -} - -void ExprEngine::evalMethodCall(const CallExpr *MCE, const CXXMethodDecl *MD, - const Expr *ThisExpr, ExplodedNode *Pred, - ExplodedNodeSet &Src, ExplodedNodeSet &Dst) { - // Allow checkers to pre-visit the member call. - ExplodedNodeSet PreVisitChecks; - getCheckerManager().runCheckersForPreStmt(PreVisitChecks, Src, MCE, *this); - - if (!(MD->isThisDeclarationADefinition() && AMgr.shouldInlineCall())) { - // FIXME: conservative method call evaluation. - getCheckerManager().runCheckersForPostStmt(Dst, PreVisitChecks, MCE, *this); - return; - } - - const StackFrameContext *SFC = AMgr.getStackFrame(MD, - Pred->getLocationContext(), - MCE, - Builder->getBlock(), - Builder->getIndex()); - const CXXThisRegion *ThisR = getCXXThisRegion(MD, SFC); - CallEnter Loc(MCE, SFC, Pred->getLocationContext()); - for (ExplodedNodeSet::iterator I = PreVisitChecks.begin(), - E = PreVisitChecks.end(); I != E; ++I) { - // Set up 'this' region. - const GRState *state = GetState(*I); - state = state->bindLoc(loc::MemRegionVal(ThisR), state->getSVal(ThisExpr)); - Dst.Add(Builder->generateNode(Loc, state, *I)); - } -} - void ExprEngine::VisitCXXNewExpr(const CXXNewExpr *CNE, ExplodedNode *Pred, ExplodedNodeSet &Dst) { if (CNE->isArray()) { diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index e90864ed36..2facd567b1 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -554,9 +554,10 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } - case Stmt::CallExprClass: { - const CallExpr* C = cast<CallExpr>(S); - VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + case Stmt::CallExprClass: + case Stmt::CXXOperatorCallExprClass: + case Stmt::CXXMemberCallExprClass: { + VisitCallExpr(cast<CallExpr>(S), Pred, Dst); break; } @@ -568,18 +569,6 @@ void ExprEngine::Visit(const Stmt* S, ExplodedNode* Pred, break; } - case Stmt::CXXMemberCallExprClass: { - const CXXMemberCallExpr *MCE = cast<CXXMemberCallExpr>(S); - VisitCXXMemberCallExpr(MCE, Pred, Dst); - break; - } - - case Stmt::CXXOperatorCallExprClass: { - const CXXOperatorCallExpr *C = cast<CXXOperatorCallExpr>(S); - VisitCXXOperatorCallExpr(C, Pred, Dst); - break; - } - case Stmt::CXXNewExprClass: { const CXXNewExpr *NE = cast<CXXNewExpr>(S); VisitCXXNewExpr(NE, Pred, Dst); @@ -1554,6 +1543,15 @@ void ExprEngine::evalLocation(ExplodedNodeSet &Dst, const Stmt *S, bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, ExplodedNode *Pred) { + return false; + + // Inlining isn't correct right now because we: + // (a) don't generate CallExit nodes. + // (b) we need a way to postpone doing post-visits of CallExprs until + // the CallExit. This means we need CallExits for the non-inline + // cases as well. + +#if 0 const GRState *state = GetState(Pred); const Expr *Callee = CE->getCallee(); SVal L = state->getSVal(Callee); @@ -1562,6 +1560,29 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, if (!FD) return false; + // Specially handle CXXMethods. + const CXXMethodDecl *methodDecl = 0; + + switch (CE->getStmtClass()) { + default: break; + case Stmt::CXXOperatorCallExprClass: { + const CXXOperatorCallExpr *opCall = cast<CXXOperatorCallExpr>(CE); + methodDecl = + llvm::dyn_cast_or_null<CXXMethodDecl>(opCall->getCalleeDecl()); + break; + } + case Stmt::CXXMemberCallExprClass: { + const CXXMemberCallExpr *memberCall = cast<CXXMemberCallExpr>(CE); + const MemberExpr *memberExpr = + cast<MemberExpr>(memberCall->getCallee()->IgnoreParens()); + methodDecl = cast<CXXMethodDecl>(memberExpr->getMemberDecl()); + break; + } + } + + + + // Check if the function definition is in the same translation unit. if (FD->hasBody(FD)) { const StackFrameContext *stackFrame = @@ -1589,14 +1610,15 @@ bool ExprEngine::InlineCall(ExplodedNodeSet &Dst, const CallExpr *CE, Dst.Add(N); return true; } + + // Generate the CallExit node. return false; +#endif } -void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, - CallExpr::const_arg_iterator AI, - CallExpr::const_arg_iterator AE, - ExplodedNodeSet& Dst) { +void ExprEngine::VisitCallExpr(const CallExpr* CE, ExplodedNode* Pred, + ExplodedNodeSet& dst) { // Determine the type of function we're calling (if available). const FunctionProtoType *Proto = NULL; @@ -1604,73 +1626,78 @@ void ExprEngine::VisitCall(const CallExpr* CE, ExplodedNode* Pred, if (const PointerType *FnTypePtr = FnType->getAs<PointerType>()) Proto = FnTypePtr->getPointeeType()->getAs<FunctionProtoType>(); - // Evaluate the arguments. - ExplodedNodeSet ArgsEvaluated; - evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, ArgsEvaluated); - - // Now process the call itself. - ExplodedNodeSet DstTmp; - const Expr* Callee = CE->getCallee()->IgnoreParens(); - - for (ExplodedNodeSet::iterator NI=ArgsEvaluated.begin(), - NE=ArgsEvaluated.end(); NI != NE; ++NI) { - // Evaluate the callee. - ExplodedNodeSet DstTmp2; - Visit(Callee, *NI, DstTmp2); - // Perform the previsit of the CallExpr, storing the results in DstTmp. - getCheckerManager().runCheckersForPreStmt(DstTmp, DstTmp2, CE, *this); + // Should the first argument be evaluated as an lvalue? + bool firstArgumentAsLvalue = false; + switch (CE->getStmtClass()) { + case Stmt::CXXOperatorCallExprClass: + firstArgumentAsLvalue = true; + break; + default: + break; } - + + // Evaluate the arguments. + ExplodedNodeSet dstArgsEvaluated; + evalArguments(CE->arg_begin(), CE->arg_end(), Proto, Pred, dstArgsEvaluated, + firstArgumentAsLvalue); + + // Evaluate the callee. + ExplodedNodeSet dstCalleeEvaluated; + evalCallee(CE, dstArgsEvaluated, dstCalleeEvaluated); + + // Perform the previsit of the CallExpr. + ExplodedNodeSet dstPreVisit; + getCheckerManager().runCheckersForPreStmt(dstPreVisit, dstCalleeEvaluated, + CE, *this); + + // Now evaluate the call itself. class DefaultEval : public GraphExpander { ExprEngine &Eng; const CallExpr *CE; public: - bool Inlined; DefaultEval(ExprEngine &eng, const CallExpr *ce) - : Eng(eng), CE(ce), Inlined(false) { } + : Eng(eng), CE(ce) {} virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) { + // Should we inline the call? if (Eng.getAnalysisManager().shouldInlineCall() && Eng.InlineCall(Dst, CE, Pred)) { - Inlined = true; - } else { - StmtNodeBuilder &Builder = Eng.getBuilder(); - assert(&Builder && "StmtNodeBuilder must be defined."); - - // Dispatch to the plug-in transfer function. - unsigned oldSize = Dst.size(); - SaveOr OldHasGen(Builder.hasGeneratedNode); - - // Dispatch to transfer function logic to handle the call itself. - const Expr* Callee = CE->getCallee()->IgnoreParens(); - const GRState* state = Eng.GetState(Pred); - SVal L = state->getSVal(Callee); - Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); - - // Handle the case where no nodes where generated. Auto-generate that - // contains the updated state if we aren't generating sinks. - if (!Builder.BuildSinks && Dst.size() == oldSize && - !Builder.hasGeneratedNode) - Eng.MakeNode(Dst, CE, Pred, state); + return; } + + StmtNodeBuilder &Builder = Eng.getBuilder(); + assert(&Builder && "StmtNodeBuilder must be defined."); + + // Dispatch to the plug-in transfer function. + unsigned oldSize = Dst.size(); + SaveOr OldHasGen(Builder.hasGeneratedNode); + + // Dispatch to transfer function logic to handle the call itself. + const Expr* Callee = CE->getCallee()->IgnoreParens(); + const GRState* state = Eng.GetState(Pred); + SVal L = state->getSVal(Callee); + Eng.getTF().evalCall(Dst, Eng, Builder, CE, L, Pred); + + // Handle the case where no nodes where generated. Auto-generate that + // contains the updated state if we aren't generating sinks. + if (!Builder.BuildSinks && Dst.size() == oldSize && + !Builder.hasGeneratedNode) + Eng.MakeNode(Dst, CE, Pred, state); } }; // Finally, evaluate the function call. We try each of the checkers // to see if the can evaluate the function call. - ExplodedNodeSet DstTmp3; + ExplodedNodeSet dstCallEvaluated; DefaultEval defEval(*this, CE); - - getCheckerManager().runCheckersForEvalCall(DstTmp3, DstTmp, CE, - *this, &defEval); - - // Callee is inlined. We shouldn't do post call checking. - if (defEval.Inlined) - return; + getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, + dstPreVisit, + CE, *this, &defEval); // Finally, perform the post-condition check of the CallExpr and store // the created nodes in 'Dst'. - getCheckerManager().runCheckersForPostStmt(Dst, DstTmp3, CE, *this); + getCheckerManager().runCheckersForPostStmt(dst, dstCallEvaluated, CE, + *this); } //===----------------------------------------------------------------------===// diff --git a/lib/StaticAnalyzer/Core/ObjCMessage.cpp b/lib/StaticAnalyzer/Core/ObjCMessage.cpp index b2272968bb..c44d36ae49 100644 --- a/lib/StaticAnalyzer/Core/ObjCMessage.cpp +++ b/lib/StaticAnalyzer/Core/ObjCMessage.cpp @@ -109,13 +109,27 @@ const Expr *ObjCMessage::getArgExpr(unsigned i) const { } QualType CallOrObjCMessage::getResultType(ASTContext &ctx) const { + QualType resultTy; + bool isLVal = false; + if (CallE) { + isLVal = CallE->isLValue(); const Expr *Callee = CallE->getCallee(); if (const FunctionDecl *FD = State->getSVal(Callee).getAsFunctionDecl()) - return FD->getResultType(); - return CallE->getType(); + resultTy = FD->getResultType(); + else + resultTy = CallE->getType(); + } + else { + isLVal = isa<ObjCMessageExpr>(Msg.getOriginExpr()) && + Msg.getOriginExpr()->isLValue(); + resultTy = Msg.getResultType(ctx); } - return Msg.getResultType(ctx); + + if (isLVal) + resultTy = ctx.getPointerType(resultTy); + + return resultTy; } SVal CallOrObjCMessage::getArgSValAsScalarOrLoc(unsigned i) const { diff --git a/test/Analysis/base-init.cpp b/test/Analysis/base-init.cpp index 828c9e0b4e..8fd7abcc37 100644 --- a/test/Analysis/base-init.cpp +++ b/test/Analysis/base-init.cpp @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-store region -analyzer-inline-call -cfg-add-initializers -verify %s +// XFAIL: * class A { int x; diff --git a/test/Analysis/inline.c b/test/Analysis/inline.c index e3c7e83893..2aac15661b 100644 --- a/test/Analysis/inline.c +++ b/test/Analysis/inline.c @@ -1,4 +1,5 @@ // RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-inline-call -analyzer-store region -verify %s +// XFAIL: * int test1_f1() { int y = 1; diff --git a/test/Analysis/misc-ps-region-store.cpp b/test/Analysis/misc-ps-region-store.cpp index 79bb03f86a..3b8d4e3782 100644 --- a/test/Analysis/misc-ps-region-store.cpp +++ b/test/Analysis/misc-ps-region-store.cpp @@ -240,3 +240,19 @@ void test_namespace() { int x = i; } +// Test handling methods that accept references as parameters, and that +// variables are properly invalidated. +class RDar9203355 { + bool foo(unsigned valA, long long &result) const; + bool foo(unsigned valA, int &result) const; +}; +bool RDar9203355::foo(unsigned valA, int &result) const { + long long val; + if (foo(valA, val) || + (int)val != val) // no-warning + return true; + result = val; // no-warning + return false; +} + + |