1// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core -fblocks -analyzer-opt-analyze-nested-blocks -verify -x objective-c++ %s
2// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpCFG -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-config cfg-rich-constructors=false %s > %t 2>&1
3// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,WARNINGS %s
4// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpCFG -fblocks -analyzer-opt-analyze-nested-blocks -analyzer-config cfg-rich-constructors=true %s > %t 2>&1
5// RUN: FileCheck --input-file=%t -check-prefixes=CHECK,ANALYZER %s
6
7// This file tests how we construct two different flavors of the Clang CFG -
8// the CFG used by the Sema analysis-based warnings and the CFG used by the
9// static analyzer. The difference in the behavior is checked via FileCheck
10// prefixes (WARNINGS and ANALYZER respectively). When introducing new analyzer
11// flags, no new run lines should be added - just these flags would go to the
12// respective line depending on where is it turned on and where is it turned
13// off. Feel free to add tests that test only one of the CFG flavors if you're
14// not sure how the other flavor is supposed to work in your case.
15
16// expected-no-diagnostics
17
18void testBlockWithoutCopyExpression(int i) {
19  // Captures i, with no copy expression.
20  (void)(^void() {
21    (void)i;
22  });
23}
24
25// CHECK-LABEL:void testBlockWithoutCopyExpression(int i)
26// CHECK-NEXT: [B2 (ENTRY)]
27// CHECK-NEXT:   Succs (1): B1
28
29// CHECK: [B1]
30// CHECK-NEXT:   1: ^{ }
31// CHECK-NEXT:   2: (void)([B1.1]) (CStyleCastExpr, ToVoid, void)
32// CHECK-NEXT:   Preds (1): B2
33// CHECK-NEXT:   Succs (1): B0
34
35// CHECK: [B0 (EXIT)]
36// CHECK-NEXT:   Preds (1): B1
37
38struct StructWithCopyConstructor {
39  StructWithCopyConstructor(int i);
40  StructWithCopyConstructor(const StructWithCopyConstructor &s);
41};
42void testBlockWithCopyExpression(StructWithCopyConstructor s) {
43  // Captures s, with a copy expression calling the copy constructor for StructWithCopyConstructor.
44  (void)(^void() {
45    (void)s;
46  });
47}
48
49// CHECK-LABEL:void testBlockWithCopyExpression(StructWithCopyConstructor s)
50// CHECK-NEXT: [B2 (ENTRY)]
51// CHECK-NEXT:   Succs (1): B1
52
53// CHECK: [B1]
54// CHECK-NEXT:   1: s
55// CHECK-NEXT:   2: [B1.1] (ImplicitCastExpr, NoOp, const struct StructWithCopyConstructor)
56// CHECK-NEXT:   3: [B1.2] (CXXConstructExpr, const struct StructWithCopyConstructor)
57// CHECK-NEXT:   4: ^{ }
58// CHECK-NEXT:   5: (void)([B1.4]) (CStyleCastExpr, ToVoid, void)
59// CHECK-NEXT:   Preds (1): B2
60// CHECK-NEXT:   Succs (1): B0
61
62// CHECK: [B0 (EXIT)]
63// CHECK-NEXT:   Preds (1): B1
64
65void testBlockWithCaptureByReference() {
66  __block StructWithCopyConstructor s(5);
67  // Captures s by reference, so no copy expression.
68  (void)(^void() {
69    (void)s;
70  });
71}
72
73// CHECK-LABEL:void testBlockWithCaptureByReference()
74// CHECK-NEXT: [B2 (ENTRY)]
75// CHECK-NEXT:   Succs (1): B1
76
77// CHECK: [B1]
78// CHECK-NEXT:   1: 5
79// WARNINGS-NEXT:   2: [B1.1] (CXXConstructExpr, struct StructWithCopyConstructor)
80// ANALYZER-NEXT:   2: [B1.1] (CXXConstructExpr, [B1.3], struct StructWithCopyConstructor)
81// CHECK-NEXT:   3: StructWithCopyConstructor s(5) __attribute__((blocks("byref")));
82// CHECK-NEXT:   4: ^{ }
83// CHECK-NEXT:   5: (void)([B1.4]) (CStyleCastExpr, ToVoid, void)
84// CHECK-NEXT:   Preds (1): B2
85// CHECK-NEXT:   Succs (1): B0
86
87// CHECK: [B0 (EXIT)]
88// CHECK-NEXT:   Preds (1): B1
89