]> granicus.if.org Git - clang/commitdiff
[analyzer] Make inlining decisions based on the callee being variadic.
authorJordan Rose <jordan_rose@apple.com>
Sat, 28 Sep 2013 02:04:19 +0000 (02:04 +0000)
committerJordan Rose <jordan_rose@apple.com>
Sat, 28 Sep 2013 02:04:19 +0000 (02:04 +0000)
...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).

<rdar://problem/15037033>

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@191599 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h
lib/StaticAnalyzer/Core/CallEvent.cpp
lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
test/Analysis/inlining/InlineObjCClassMethod.m

index 1b928af17d9f282342d1850ed089322e75858321..cfaf085b5f343f5e514ad1a54ef61a4fe4a37f5c 100644 (file)
@@ -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<QualType, ParmVarDecl> 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();
index ce66363413fc3bd2893e9131397b737c6f9d335f..a3b34f4790a9784741bf32bc11129d01cb64ba2c 100644 (file)
@@ -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<FunctionDecl>(D))
+    return FD->isVariadic();
+  if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D))
+    return MD->isVariadic();
+  if (const BlockDecl *BD = dyn_cast<BlockDecl>(D))
+    return BD->isVariadic();
+
+  llvm_unreachable("unknown callable kind");
 }
 
 static void addParameterValuesToBindings(const StackFrameContext *CalleeCtx,
index 08d239edab7b41fec8419a482130cb2735f00a9f..06328e4ffce993f6e7cd56887dea9d85d3ecdc44 100644 (file)
@@ -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);
index 90ce3c051babcd3aeabc043d71c4fca9b1a7d5d4..6efcb894fecd63e6eb62ada5c26099c3e023b4cc 100644 (file)
@@ -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
+
+
+