diff options
author | Anna Zaks <ganna@apple.com> | 2012-08-10 18:55:53 +0000 |
---|---|---|
committer | Anna Zaks <ganna@apple.com> | 2012-08-10 18:55:53 +0000 |
commit | 3f558af01643787d209a133215b0abec81b5fe30 (patch) | |
tree | 305fe3ecf8fc39d9ab0b044cd53d18e0420ea3bd /lib/StaticAnalyzer/Core/CallEvent.cpp | |
parent | a1fa47139d6e9e7dcc40f2809605d1a258624e7f (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.cpp | 61 |
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. |