From: Jordan Rose Date: Sat, 28 Sep 2013 02:04:19 +0000 (+0000) Subject: [analyzer] Make inlining decisions based on the callee being variadic. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=9b072b31ee2f41b8e30d1d22142c9ab72ac5ff1f;p=clang [analyzer] Make inlining decisions based on the callee being variadic. ...rather than trying to figure it out from the call site, and having people complain that we guessed wrong and that a prototype-less call is the same as a variadic call on their system. More importantly, fix a crash when there's no decl at the call site (though we could have just returned a default value). git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191599 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h index 1b928af17d..cfaf085b5f 100644 --- a/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h +++ b/include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h @@ -228,11 +228,6 @@ public: return false; } - /// \brief Returns true if this is a call to a variadic function or method. - virtual bool isVariadic() const { - return false; - } - /// \brief Returns a source range for the entire call, suitable for /// outputting in diagnostics. virtual SourceRange getSourceRange() const { @@ -341,6 +336,11 @@ public: /// This will return a null QualType if the result type cannot be determined. static QualType getDeclaredResultType(const Decl *D); + /// \brief Returns true if the given decl is known to be variadic. + /// + /// \p D must not be null. + static bool isVariadic(const Decl *D); + // Iterator access to formal parameters and their types. private: typedef std::const_mem_fun_t get_type_fun; @@ -417,10 +417,6 @@ public: return RuntimeDefinition(); } - virtual bool isVariadic() const { - return getDecl()->isVariadic(); - } - virtual bool argumentsMayEscape() const; virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, @@ -521,10 +517,6 @@ public: return RuntimeDefinition(getBlockDecl()); } - virtual bool isVariadic() const { - return getBlockDecl()->isVariadic(); - } - virtual void getInitialStackFrameContents(const StackFrameContext *CalleeCtx, BindingsTy &Bindings) const; @@ -843,9 +835,6 @@ public: virtual const Expr *getArgExpr(unsigned Index) const { return getOriginExpr()->getArg(Index); } - virtual bool isVariadic() const { - return getDecl()->isVariadic(); - } bool isInstanceMessage() const { return getOriginExpr()->isInstanceMessage(); diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp index ce66363413..a3b34f4790 100644 --- a/lib/StaticAnalyzer/Core/CallEvent.cpp +++ b/lib/StaticAnalyzer/Core/CallEvent.cpp @@ -264,7 +264,20 @@ QualType CallEvent::getDeclaredResultType(const Decl *D) { return QualType(); } - return QualType(); + llvm_unreachable("unknown callable kind"); +} + +bool CallEvent::isVariadic(const Decl *D) { + assert(D); + + if (const FunctionDecl *FD = dyn_cast(D)) + return FD->isVariadic(); + if (const ObjCMethodDecl *MD = dyn_cast(D)) + return MD->isVariadic(); + if (const BlockDecl *BD = dyn_cast(D)) + return BD->isVariadic(); + + llvm_unreachable("unknown callable kind"); } static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx, diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index 08d239edab..06328e4ffc 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -740,10 +740,10 @@ static bool isCXXSharedPtrDtor(const FunctionDecl *FD) { /// This checks static properties of the function, such as its signature and /// CFG, to determine whether the analyzer should ever consider inlining it, /// in any context. -static bool mayInlineDecl(const CallEvent &Call, AnalysisDeclContext *CalleeADC, +static bool mayInlineDecl(AnalysisDeclContext *CalleeADC, AnalyzerOptions &Opts) { // FIXME: Do not inline variadic calls. - if (Call.isVariadic()) + if (CallEvent::isVariadic(CalleeADC->getDecl())) return false; // Check certain C++-related inlining policies. @@ -833,7 +833,7 @@ bool ExprEngine::shouldInlineCall(const CallEvent &Call, const Decl *D, } else { // We haven't actually checked the static properties of this function yet. // Do that now, and record our decision in the function summaries. - if (mayInlineDecl(Call, CalleeADC, Opts)) { + if (mayInlineDecl(CalleeADC, Opts)) { Engine.FunctionSummaries->markMayInline(D); } else { Engine.FunctionSummaries->markShouldNotInline(D); diff --git a/test/Analysis/inlining/InlineObjCClassMethod.m b/test/Analysis/inlining/InlineObjCClassMethod.m index 90ce3c051b..6efcb894fe 100644 --- a/test/Analysis/inlining/InlineObjCClassMethod.m +++ b/test/Analysis/inlining/InlineObjCClassMethod.m @@ -1,4 +1,6 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=core -analyzer-config ipa=dynamic-bifurcate -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -analyzer-config ipa=dynamic-bifurcate -verify %s + +void clang_analyzer_checkInlined(int); // Test inlining of ObjC class methods. @@ -209,3 +211,26 @@ int checkSelfUsedInparentClassMethod() { return 5/[SelfUsedInParentChild fooA]; } + +@interface Rdar15037033 : NSObject +@end + +void rdar15037033() { + [Rdar15037033 forwardDeclaredMethod]; // expected-warning {{class method '+forwardDeclaredMethod' not found}} + [Rdar15037033 forwardDeclaredVariadicMethod:1, 2, 3, 0]; // expected-warning {{class method '+forwardDeclaredVariadicMethod:' not found}} +} + +@implementation Rdar15037033 + ++ (void)forwardDeclaredMethod { + clang_analyzer_checkInlined(1); // expected-warning{{TRUE}} +} + ++ (void)forwardDeclaredVariadicMethod:(int)x, ... { + clang_analyzer_checkInlined(0); // no-warning +} + +@end + + +