150
|
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
|
|
18 void 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
|
|
38 struct StructWithCopyConstructor {
|
|
39 StructWithCopyConstructor(int i);
|
|
40 StructWithCopyConstructor(const StructWithCopyConstructor &s);
|
|
41 };
|
|
42 void 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
|
|
65 void 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
|