aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/CallEvent.cpp
diff options
context:
space:
mode:
authorAnna Zaks <ganna@apple.com>2012-08-10 18:55:53 +0000
committerAnna Zaks <ganna@apple.com>2012-08-10 18:55:53 +0000
commit3f558af01643787d209a133215b0abec81b5fe30 (patch)
tree305fe3ecf8fc39d9ab0b044cd53d18e0420ea3bd /lib/StaticAnalyzer/Core/CallEvent.cpp
parenta1fa47139d6e9e7dcc40f2809605d1a258624e7f (diff)
[analyzer] Optimize dynamic dispatch bifurcation by detecting the cases
when we don't need to split. In some cases we know that a method cannot have a different implementation in a subclass: - the class is declared in the main file (private) - all the method declarations (including the ones coming from super classes) are in the main file. This can be improved further, but might be enough for the heuristic. (When we are too aggressive splitting the state, efficiency suffers. When we fail to split the state coverage might suffer.) git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161681 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/StaticAnalyzer/Core/CallEvent.cpp')
-rw-r--r--lib/StaticAnalyzer/Core/CallEvent.cpp61
1 files changed, 59 insertions, 2 deletions
diff --git a/lib/StaticAnalyzer/Core/CallEvent.cpp b/lib/StaticAnalyzer/Core/CallEvent.cpp
index 13bdaa729b..773600b096 100644
--- a/lib/StaticAnalyzer/Core/CallEvent.cpp
+++ b/lib/StaticAnalyzer/Core/CallEvent.cpp
@@ -659,6 +659,59 @@ ObjCMessageKind ObjCMethodCall::getMessageKind() const {
return static_cast<ObjCMessageKind>(Info.getInt());
}
+
+bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl,
+ Selector Sel) const {
+ assert(IDecl);
+ const SourceManager &SM =
+ getState()->getStateManager().getContext().getSourceManager();
+
+ // If the class interface is declared inside the main file, assume it is not
+ // subcassed.
+ // TODO: It could actually be subclassed if the subclass is private as well.
+ // This is probably very rare.
+ SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc();
+ if (InterfLoc.isValid() && SM.isFromMainFile(InterfLoc))
+ return false;
+
+
+ // We assume that if the method is public (declared outside of main file) or
+ // has a parent which publicly declares the method, the method could be
+ // overridden in a subclass.
+
+ // Find the first declaration in the class hierarchy that declares
+ // the selector.
+ ObjCMethodDecl *D = 0;
+ while (true) {
+ D = IDecl->lookupMethod(Sel, true);
+
+ // Cannot find a public definition.
+ if (!D)
+ return false;
+
+ // If outside the main file,
+ if (D->getLocation().isValid() && !SM.isFromMainFile(D->getLocation()))
+ return true;
+
+ if (D->isOverriding()) {
+ // Search in the superclass on the next iteration.
+ IDecl = D->getClassInterface();
+ if (!IDecl)
+ return false;
+
+ IDecl = IDecl->getSuperClass();
+ if (!IDecl)
+ return false;
+
+ continue;
+ }
+
+ return false;
+ };
+
+ llvm_unreachable("The while loop should always terminate.");
+}
+
RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
const ObjCMessageExpr *E = getOriginExpr();
assert(E);
@@ -686,8 +739,12 @@ RuntimeDefinition ObjCMethodCall::getRuntimeDefinition() const {
// Lookup the method implementation.
if (ReceiverT)
- if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl())
- return RuntimeDefinition(IDecl->lookupPrivateMethod(Sel), Receiver);
+ if (ObjCInterfaceDecl *IDecl = ReceiverT->getInterfaceDecl()) {
+ if (canBeOverridenInSubclass(IDecl, Sel))
+ return RuntimeDefinition(IDecl->lookupPrivateMethod(Sel), Receiver);
+ else
+ return RuntimeDefinition(IDecl->lookupPrivateMethod(Sel), 0);
+ }
} else {
// This is a class method.