Summary: Objective-C Class objects can be used to do a dynamic dispatch on class methods. The analyzer had a few places where we tried to overcome the dynamic nature of it and still guess the actual function that is being called. That was done mostly using some simple heuristics covering the most widespread cases (e.g. [[self class] classmethod]). This solution introduces a way to track types represented by Class objects and work with that instead of direct AST matching. rdar://problem/50739539 Differential Revision: https://reviews.llvm.org/D78286
48 lines
1.6 KiB
C++
48 lines
1.6 KiB
C++
// RUN: %clang_analyze_cc1 -std=c++14 \
|
|
// RUN: -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection\
|
|
// RUN: -analyzer-output=text -verify %s 2>&1 | FileCheck %s
|
|
|
|
#include "Inputs/llvm.h"
|
|
|
|
void clang_analyzer_printState();
|
|
|
|
namespace clang {
|
|
struct Shape {};
|
|
class Triangle : public Shape {};
|
|
class Circle : public Shape {};
|
|
class Square : public Shape {};
|
|
} // namespace clang
|
|
|
|
using namespace llvm;
|
|
using namespace clang;
|
|
|
|
void evalNonNullParamNonNullReturn(const Shape *S) {
|
|
const auto *C = dyn_cast_or_null<Circle>(S);
|
|
// expected-note@-1 {{Assuming 'S' is a 'Circle'}}
|
|
// expected-note@-2 {{'C' initialized here}}
|
|
|
|
// FIXME: We assumed that 'S' is a 'Circle' therefore it is not a 'Square'.
|
|
if (dyn_cast_or_null<Square>(S)) {
|
|
// expected-note@-1 {{Assuming 'S' is not a 'Square'}}
|
|
// expected-note@-2 {{Taking false branch}}
|
|
return;
|
|
}
|
|
|
|
clang_analyzer_printState();
|
|
|
|
// CHECK: "dynamic_types": [
|
|
// CHECK-NEXT: { "region": "SymRegion{reg_$0<const struct clang::Shape * S>}", "dyn_type": "const class clang::Circle", "sub_classable": true }
|
|
// CHECK-NEXT: ],
|
|
// CHECK-NEXT: "dynamic_casts": [
|
|
// CHECK: { "region": "SymRegion{reg_$0<const struct clang::Shape * S>}", "casts": [
|
|
// CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const class clang::Circle *", "kind": "success" },
|
|
// CHECK-NEXT: { "from": "const struct clang::Shape *", "to": "const class clang::Square *", "kind": "fail" }
|
|
// CHECK-NEXT: ] }
|
|
|
|
(void)(1 / !C);
|
|
// expected-note@-1 {{'C' is non-null}}
|
|
// expected-note@-2 {{Division by zero}}
|
|
// expected-warning@-3 {{Division by zero}}
|
|
}
|
|
|