aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Core/CallEvent.cpp
diff options
context:
space:
mode:
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.