summaryrefslogtreecommitdiffstats
path: root/test/Analysis
diff options
context:
space:
mode:
authorDavid L. Jones <dlj@google.com>2017-11-10 01:07:01 +0000
committerDavid L. Jones <dlj@google.com>2017-11-10 01:07:01 +0000
commit41af1698c520ea38edf83e7c91f1e519d34f20c1 (patch)
tree05c516cb7514d80a5e8deccb07cd0f7c228b70d4 /test/Analysis
parentcd1b175aa96d9d675c09fc54dfd96ba41e3f2279 (diff)
parent4d085086c74a8fbce197f61548f488a63f300933 (diff)
Creating branches/google/testing and tags/google/testing/ from r317203
git-svn-id: https://llvm.org/svn/llvm-project/cfe/branches/google/testing@317856 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Analysis')
-rw-r--r--test/Analysis/DeleteWithNonVirtualDtor.cpp187
-rw-r--r--test/Analysis/DynamicTypePropagation.m12
-rw-r--r--test/Analysis/Inputs/system-header-simulator-cxx.h387
-rw-r--r--test/Analysis/MismatchedDeallocator-path-notes.cpp2
-rw-r--r--test/Analysis/MisusedMovedObject.cpp675
-rw-r--r--test/Analysis/NewDelete-path-notes.cpp4
-rw-r--r--test/Analysis/additive-folding.cpp9
-rw-r--r--test/Analysis/analyzer-config.c11
-rw-r--r--test/Analysis/analyzer-config.cpp10
-rw-r--r--test/Analysis/analyzer_test.py43
-rw-r--r--test/Analysis/bitwise-ops.c27
-rw-r--r--test/Analysis/block-in-critical-section.cpp42
-rw-r--r--test/Analysis/block-in-critical-section.m10
-rw-r--r--test/Analysis/bstring.cpp41
-rw-r--r--test/Analysis/bug_hash_test.cpp1423
-rw-r--r--test/Analysis/bug_hash_test.m1182
-rw-r--r--test/Analysis/builtin-functions.cpp14
-rw-r--r--test/Analysis/call_once.cpp305
-rw-r--r--test/Analysis/casts.c31
-rw-r--r--test/Analysis/compound-literals.c9
-rw-r--r--test/Analysis/conversion.c70
-rw-r--r--test/Analysis/copypaste/asm.cpp2
-rw-r--r--test/Analysis/copypaste/attributes.cpp2
-rw-r--r--test/Analysis/copypaste/autogenerated_automoc.cpp19
-rw-r--r--test/Analysis/copypaste/blocks.cpp2
-rw-r--r--test/Analysis/copypaste/call.cpp2
-rw-r--r--test/Analysis/copypaste/catch.cpp2
-rw-r--r--test/Analysis/copypaste/dbus_autogenerated.cpp19
-rw-r--r--test/Analysis/copypaste/delete.cpp2
-rw-r--r--test/Analysis/copypaste/dependent-exist.cpp2
-rw-r--r--test/Analysis/copypaste/expr-types.cpp2
-rw-r--r--test/Analysis/copypaste/fold.cpp2
-rw-r--r--test/Analysis/copypaste/function-try-block.cpp2
-rw-r--r--test/Analysis/copypaste/functions.cpp2
-rw-r--r--test/Analysis/copypaste/generic.c2
-rw-r--r--test/Analysis/copypaste/labels.cpp2
-rw-r--r--test/Analysis/copypaste/lambda.cpp2
-rw-r--r--test/Analysis/copypaste/macros.cpp2
-rw-r--r--test/Analysis/copypaste/moc_autogenerated.cpp19
-rw-r--r--test/Analysis/copypaste/not-autogenerated.cpp14
-rw-r--r--test/Analysis/copypaste/objc-methods.m2
-rw-r--r--test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp2
-rw-r--r--test/Analysis/copypaste/plist-diagnostics.cpp2
-rw-r--r--test/Analysis/copypaste/sub-sequences.cpp2
-rw-r--r--test/Analysis/copypaste/suspicious-clones.cpp2
-rw-r--r--test/Analysis/copypaste/text-diagnostics.cpp2
-rw-r--r--test/Analysis/copypaste/ui_autogenerated.cpp19
-rw-r--r--test/Analysis/ctor.mm28
-rw-r--r--test/Analysis/diagnostics/diag-cross-file-boundaries.c12
-rw-r--r--test/Analysis/diagnostics/explicit-suppression.cpp2
-rw-r--r--test/Analysis/diagnostics/report-issues-within-main-file.cpp2
-rw-r--r--test/Analysis/edges-new.mm6
-rw-r--r--test/Analysis/enum.cpp43
-rw-r--r--test/Analysis/exercise-ps.c8
-rw-r--r--test/Analysis/expr-inspection.c3
-rw-r--r--test/Analysis/func-mapping-test.cpp7
-rw-r--r--test/Analysis/gmalloc.c110
-rw-r--r--test/Analysis/gtest.cpp14
-rw-r--r--test/Analysis/html-diag-singlefile.c14
-rw-r--r--test/Analysis/html-diag-singlefile.h (renamed from test/Analysis/diagnostics/diag-cross-file-boundaries.h)0
-rw-r--r--test/Analysis/html-diags-analyze-headers.c10
-rw-r--r--test/Analysis/html-diags-analyze-headers.h5
-rw-r--r--test/Analysis/html-diags-multifile.c5
-rw-r--r--test/Analysis/html-diags.c18
-rw-r--r--test/Analysis/initializer.cpp18
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.c53
-rw-r--r--test/Analysis/inlining/inline-defensive-checks.cpp15
-rw-r--r--test/Analysis/iterator-past-end.cpp205
-rw-r--r--test/Analysis/iterator-range.cpp19
-rw-r--r--test/Analysis/lifetime-cfg-output.cpp783
-rw-r--r--test/Analysis/lit.local.cfg33
-rw-r--r--test/Analysis/localization-aggressive.m19
-rw-r--r--test/Analysis/loop-unrolling.cpp381
-rw-r--r--test/Analysis/loopexit-cfg-output.cpp476
-rw-r--r--test/Analysis/malloc-overflow2.c6
-rw-r--r--test/Analysis/malloc-plist.c36
-rw-r--r--test/Analysis/malloc.c10
-rw-r--r--test/Analysis/malloc.mm2
-rw-r--r--test/Analysis/max-nodes-suppress-on-sink.c52
-rw-r--r--test/Analysis/max-nodes-suppress-on-sink.cpp34
-rw-r--r--test/Analysis/nonnull-global-constants.mm103
-rw-r--r--test/Analysis/null-deref-offsets.c37
-rw-r--r--test/Analysis/null-deref-path-notes.c9
-rw-r--r--test/Analysis/null-deref-path-notes.cpp25
-rw-r--r--test/Analysis/null-deref-path-notes.m240
-rw-r--r--test/Analysis/null-deref-ps-region.c61
-rw-r--r--test/Analysis/null-deref-ps.c4
-rw-r--r--test/Analysis/nullability-notes.m204
-rw-r--r--test/Analysis/nullptr.cpp65
-rw-r--r--test/Analysis/objc-boxing.m35
-rw-r--r--test/Analysis/objc-encode.m9
-rw-r--r--test/Analysis/objc-for.m19
-rw-r--r--test/Analysis/plist-macros.cpp4
-rw-r--r--test/Analysis/pointer-arithmetic.c30
-rw-r--r--test/Analysis/properties.m16
-rw-r--r--test/Analysis/pthreadlock.c79
-rw-r--r--test/Analysis/ptr-arith.c5
-rw-r--r--test/Analysis/ptr-arith.cpp19
-rw-r--r--test/Analysis/reference.cpp11
-rw-r--r--test/Analysis/retain-release-inline.m90
-rw-r--r--test/Analysis/retain-release-safe.c72
-rw-r--r--test/Analysis/retain-release.m19
-rw-r--r--test/Analysis/retain-release.mm9
-rw-r--r--test/Analysis/simple-stream-checks.c2
-rw-r--r--test/Analysis/taint-generic.c41
-rw-r--r--test/Analysis/temp-obj-dtors-cfg-output.cpp81
-rw-r--r--test/Analysis/temporaries-callback-order.cpp36
-rw-r--r--test/Analysis/temporaries.cpp27
-rw-r--r--test/Analysis/uninit-const.cpp2
-rw-r--r--test/Analysis/unix-fns.c4
-rw-r--r--test/Analysis/unreachable-code-path.c10
-rw-r--r--test/Analysis/unsupported-types.c31
-rw-r--r--test/Analysis/virtualcall.cpp281
-rw-r--r--test/Analysis/virtualcall.h32
114 files changed, 5747 insertions, 3020 deletions
diff --git a/test/Analysis/DeleteWithNonVirtualDtor.cpp b/test/Analysis/DeleteWithNonVirtualDtor.cpp
new file mode 100644
index 0000000000..a9b8a11f34
--- /dev/null
+++ b/test/Analysis/DeleteWithNonVirtualDtor.cpp
@@ -0,0 +1,187 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.DeleteWithNonVirtualDtor -std=c++11 -verify -analyzer-output=text %s
+
+struct Virtual {
+ virtual ~Virtual() {}
+};
+
+struct VDerived : public Virtual {};
+
+struct NonVirtual {
+ ~NonVirtual() {}
+};
+
+struct NVDerived : public NonVirtual {};
+struct NVDoubleDerived : public NVDerived {};
+
+struct Base {
+ virtual void destroy() = 0;
+};
+
+class PrivateDtor final : public Base {
+public:
+ void destroy() { delete this; }
+private:
+ ~PrivateDtor() {}
+};
+
+struct ImplicitNV {
+ virtual void f();
+};
+
+struct ImplicitNVDerived : public ImplicitNV {};
+
+NVDerived *get();
+
+NonVirtual *create() {
+ NonVirtual *x = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ return x;
+}
+
+void sink(NonVirtual *x) {
+ delete x; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void sinkCast(NonVirtual *y) {
+ delete reinterpret_cast<NVDerived*>(y);
+}
+
+void sinkParamCast(NVDerived *z) {
+ delete z;
+}
+
+void singleDerived() {
+ NonVirtual *sd;
+ sd = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete sd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void singleDerivedArr() {
+ NonVirtual *sda = new NVDerived[5]; // expected-note{{Conversion from derived to base happened here}}
+ delete[] sda; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleDerived() {
+ NonVirtual *dd = new NVDoubleDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete (dd); // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void assignThroughFunction() {
+ NonVirtual *atf = get(); // expected-note{{Conversion from derived to base happened here}}
+ delete atf; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void assignThroughFunction2() {
+ NonVirtual *atf2;
+ atf2 = get(); // expected-note{{Conversion from derived to base happened here}}
+ delete atf2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void createThroughFunction() {
+ NonVirtual *ctf = create(); // expected-note{{Calling 'create'}}
+ // expected-note@-1{{Returning from 'create'}}
+ delete ctf; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void deleteThroughFunction() {
+ NonVirtual *dtf = new NVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ sink(dtf); // expected-note{{Calling 'sink'}}
+}
+
+void singleCastCStyle() {
+ NVDerived *sccs = new NVDerived();
+ NonVirtual *sccs2 = (NonVirtual*)sccs; // expected-note{{Conversion from derived to base happened here}}
+ delete sccs2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleCastCStyle() {
+ NonVirtual *dccs = new NVDerived();
+ NVDerived *dccs2 = (NVDerived*)dccs;
+ dccs = (NonVirtual*)dccs2; // expected-note{{Conversion from derived to base happened here}}
+ delete dccs; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void singleCast() {
+ NVDerived *sc = new NVDerived();
+ NonVirtual *sc2 = reinterpret_cast<NonVirtual*>(sc); // expected-note{{Conversion from derived to base happened here}}
+ delete sc2; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleCast() {
+ NonVirtual *dd = new NVDerived();
+ NVDerived *dd2 = reinterpret_cast<NVDerived*>(dd);
+ dd = reinterpret_cast<NonVirtual*>(dd2); // expected-note {{Conversion from derived to base happened here}}
+ delete dd; // expected-warning {{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void implicitNV() {
+ ImplicitNV *invd = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete invd; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void doubleDecl() {
+ ImplicitNV *dd1, *dd2;
+ dd1 = new ImplicitNVDerived(); // expected-note{{Conversion from derived to base happened here}}
+ delete dd1; // expected-warning{{Destruction of a polymorphic object with no virtual destructor}}
+ // expected-note@-1{{Destruction of a polymorphic object with no virtual destructor}}
+}
+
+void virtualBase() {
+ Virtual *vb = new VDerived();
+ delete vb; // no-warning
+}
+
+void notDerived() {
+ NonVirtual *nd = new NonVirtual();
+ delete nd; // no-warning
+}
+
+void notDerivedArr() {
+ NonVirtual *nda = new NonVirtual[3];
+ delete[] nda; // no-warning
+}
+
+void cast() {
+ NonVirtual *c = new NVDerived();
+ delete reinterpret_cast<NVDerived*>(c); // no-warning
+}
+
+void deleteThroughFunction2() {
+ NonVirtual *dtf2 = new NVDerived();
+ sinkCast(dtf2); // no-warning
+}
+
+void deleteThroughFunction3() {
+ NVDerived *dtf3;
+ dtf3 = new NVDerived();
+ sinkParamCast(dtf3); // no-warning
+}
+
+void stackVar() {
+ NonVirtual sv2;
+ delete &sv2; // no-warning
+}
+
+// Deleting a polymorphic object with a non-virtual dtor
+// is not a problem if it is referenced by its precise type.
+
+void preciseType() {
+ NVDerived *pt = new NVDerived();
+ delete pt; // no-warning
+}
+
+void privateDtor() {
+ Base *pd = new PrivateDtor();
+ pd->destroy(); // no-warning
+}
diff --git a/test/Analysis/DynamicTypePropagation.m b/test/Analysis/DynamicTypePropagation.m
index 25a0ae35fd..63904b8425 100644
--- a/test/Analysis/DynamicTypePropagation.m
+++ b/test/Analysis/DynamicTypePropagation.m
@@ -4,6 +4,9 @@
# error Compiler does not support Objective-C generics?
#endif
+typedef __typeof(sizeof(int)) size_t;
+void *memset(void *, int, size_t);
+
#define nil 0
typedef unsigned long NSUInteger;
typedef int BOOL;
@@ -21,6 +24,7 @@ __attribute__((objc_root_class))
@end
@interface NSArray<ObjectType> : NSObject
+- (void) init;
- (BOOL)contains:(ObjectType)obj;
- (ObjectType)getObjAtIndex:(NSUInteger)idx;
- (ObjectType)objectAtIndexedSubscript:(NSUInteger)idx;
@@ -55,3 +59,11 @@ void testArgument(NSArray<MyType *> *arr, id element) {
// MyType!
[element myFunction:0 myParam:0 ];
}
+
+// Do not try this at home! The analyzer shouldn't crash though when it
+// tries to figure out the dynamic type behind the alloca's return value.
+void testAlloca(size_t NSArrayClassSizeWeKnowSomehow) {
+ NSArray *arr = __builtin_alloca(NSArrayClassSizeWeKnowSomehow);
+ memset(arr, 0, NSArrayClassSizeWeKnowSomehow);
+ [arr init]; // no-crash
+}
diff --git a/test/Analysis/Inputs/system-header-simulator-cxx.h b/test/Analysis/Inputs/system-header-simulator-cxx.h
index 005e7f57af..809b768d71 100644
--- a/test/Analysis/Inputs/system-header-simulator-cxx.h
+++ b/test/Analysis/Inputs/system-header-simulator-cxx.h
@@ -8,18 +8,61 @@
typedef unsigned char uint8_t;
typedef __typeof__(sizeof(int)) size_t;
+typedef __typeof__((char*)0-(char*)0) ptrdiff_t;
void *memmove(void *s1, const void *s2, size_t n);
-template <typename T, typename Ptr, typename Ref> struct __iterator {
- typedef __iterator<T, T *, T &> iterator;
- typedef __iterator<T, const T *, const T &> const_iterator;
+namespace std {
+ struct input_iterator_tag { };
+ struct output_iterator_tag { };
+ struct forward_iterator_tag : public input_iterator_tag { };
+ struct bidirectional_iterator_tag : public forward_iterator_tag { };
+ struct random_access_iterator_tag : public bidirectional_iterator_tag { };
- __iterator(const Ptr p) : ptr(p) {}
+ template <typename Iterator> struct iterator_traits {
+ typedef typename Iterator::difference_type difference_type;
+ typedef typename Iterator::value_type value_type;
+ typedef typename Iterator::pointer pointer;
+ typedef typename Iterator::reference reference;
+ typedef typename Iterator::iterator_category iterator_category;
+ };
+}
+
+template <typename T, typename Ptr, typename Ref> struct __vector_iterator {
+ typedef __vector_iterator<T, T *, T &> iterator;
+ typedef __vector_iterator<T, const T *, const T &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::random_access_iterator_tag iterator_category;
+
+ __vector_iterator(const Ptr p = 0) : ptr(p) {}
+ __vector_iterator(const iterator &rhs): ptr(rhs.base()) {}
+ __vector_iterator<T, Ptr, Ref> operator++() { ++ ptr; return *this; }
+ __vector_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ ++ ptr;
+ return tmp;
+ }
+ __vector_iterator<T, Ptr, Ref> operator--() { -- ptr; return *this; }
+ __vector_iterator<T, Ptr, Ref> operator--(int) {
+ auto tmp = *this; -- ptr;
+ return tmp;
+ }
+ __vector_iterator<T, Ptr, Ref> operator+(difference_type n) {
+ return ptr + n;
+ }
+ __vector_iterator<T, Ptr, Ref> operator-(difference_type n) {
+ return ptr - n;
+ }
+ __vector_iterator<T, Ptr, Ref> operator+=(difference_type n) {
+ return ptr += n;
+ }
+ __vector_iterator<T, Ptr, Ref> operator-=(difference_type n) {
+ return ptr -= n;
+ }
- __iterator<T, Ptr, Ref> operator++() { return *this; }
- __iterator<T, Ptr, Ref> operator++(int) { return *this; }
- __iterator<T, Ptr, Ref> operator--() { return *this; }
- __iterator<T, Ptr, Ref> operator--(int) { return *this; }
Ref operator*() const { return *ptr; }
Ptr operator->() const { return *ptr; }
@@ -29,10 +72,136 @@ template <typename T, typename Ptr, typename Ref> struct __iterator {
bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; }
bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; }
+ const Ptr& base() const { return ptr; }
+
private:
Ptr ptr;
};
+template <typename T, typename Ptr, typename Ref> struct __deque_iterator {
+ typedef __deque_iterator<T, T *, T &> iterator;
+ typedef __deque_iterator<T, const T *, const T &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::random_access_iterator_tag iterator_category;
+
+ __deque_iterator(const Ptr p = 0) : ptr(p) {}
+ __deque_iterator(const iterator &rhs): ptr(rhs.base()) {}
+ __deque_iterator<T, Ptr, Ref> operator++() { ++ ptr; return *this; }
+ __deque_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ ++ ptr;
+ return tmp;
+ }
+ __deque_iterator<T, Ptr, Ref> operator--() { -- ptr; return *this; }
+ __deque_iterator<T, Ptr, Ref> operator--(int) {
+ auto tmp = *this; -- ptr;
+ return tmp;
+ }
+ __deque_iterator<T, Ptr, Ref> operator+(difference_type n) {
+ return ptr + n;
+ }
+ __deque_iterator<T, Ptr, Ref> operator-(difference_type n) {
+ return ptr - n;
+ }
+ __deque_iterator<T, Ptr, Ref> operator+=(difference_type n) {
+ return ptr += n;
+ }
+ __deque_iterator<T, Ptr, Ref> operator-=(difference_type n) {
+ return ptr -= n;
+ }
+
+ Ref operator*() const { return *ptr; }
+ Ptr operator->() const { return *ptr; }
+
+ bool operator==(const iterator &rhs) const { return ptr == rhs.ptr; }
+ bool operator==(const const_iterator &rhs) const { return ptr == rhs.ptr; }
+
+ bool operator!=(const iterator &rhs) const { return ptr != rhs.ptr; }
+ bool operator!=(const const_iterator &rhs) const { return ptr != rhs.ptr; }
+
+ const Ptr& base() const { return ptr; }
+
+private:
+ Ptr ptr;
+};
+
+template <typename T, typename Ptr, typename Ref> struct __list_iterator {
+ typedef __list_iterator<T, __typeof__(T::data) *, __typeof__(T::data) &> iterator;
+ typedef __list_iterator<T, const __typeof__(T::data) *, const __typeof__(T::data) &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::bidirectional_iterator_tag iterator_category;
+
+ __list_iterator(T* it = 0) : item(it) {}
+ __list_iterator(const iterator &rhs): item(rhs.base()) {}
+ __list_iterator<T, Ptr, Ref> operator++() { item = item->next; return *this; }
+ __list_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ item = item->next;
+ return tmp;
+ }
+ __list_iterator<T, Ptr, Ref> operator--() { item = item->prev; return *this; }
+ __list_iterator<T, Ptr, Ref> operator--(int) {
+ auto tmp = *this;
+ item = item->prev;
+ return tmp;
+ }
+
+ Ref operator*() const { return item->data; }
+ Ptr operator->() const { return item->data; }
+
+ bool operator==(const iterator &rhs) const { return item == rhs->item; }
+ bool operator==(const const_iterator &rhs) const { return item == rhs->item; }
+
+ bool operator!=(const iterator &rhs) const { return item != rhs->item; }
+ bool operator!=(const const_iterator &rhs) const { return item != rhs->item; }
+
+ const T* &base() const { return item; }
+
+private:
+ T* item;
+};
+
+template <typename T, typename Ptr, typename Ref> struct __fwdl_iterator {
+ typedef __fwdl_iterator<T, __typeof__(T::data) *, __typeof__(T::data) &> iterator;
+ typedef __fwdl_iterator<T, const __typeof__(T::data) *, const __typeof__(T::data) &> const_iterator;
+
+ typedef ptrdiff_t difference_type;
+ typedef T value_type;
+ typedef Ptr pointer;
+ typedef Ref reference;
+ typedef std::forward_iterator_tag iterator_category;
+
+ __fwdl_iterator(T* it = 0) : item(it) {}
+ __fwdl_iterator(const iterator &rhs): item(rhs.base()) {}
+ __fwdl_iterator<T, Ptr, Ref> operator++() { item = item->next; return *this; }
+ __fwdl_iterator<T, Ptr, Ref> operator++(int) {
+ auto tmp = *this;
+ item = item->next;
+ return tmp;
+ }
+ Ref operator*() const { return item->data; }
+ Ptr operator->() const { return item->data; }
+
+ bool operator==(const iterator &rhs) const { return item == rhs->item; }
+ bool operator==(const const_iterator &rhs) const { return item == rhs->item; }
+
+ bool operator!=(const iterator &rhs) const { return item != rhs->item; }
+ bool operator!=(const const_iterator &rhs) const { return item != rhs->item; }
+
+ const T* &base() const { return item; }
+
+private:
+ T* item;
+};
+
namespace std {
template <class T1, class T2>
struct pair {
@@ -43,30 +212,124 @@ namespace std {
pair(const T1 &a, const T2 &b) : first(a), second(b) {}
template<class U1, class U2>
- pair(const pair<U1, U2> &other) : first(other.first), second(other.second) {}
+ pair(const pair<U1, U2> &other) : first(other.first),
+ second(other.second) {}
};
typedef __typeof__(sizeof(int)) size_t;
+
+ template <class T> class initializer_list;
+ template< class T > struct remove_reference {typedef T type;};
+ template< class T > struct remove_reference<T&> {typedef T type;};
+ template< class T > struct remove_reference<T&&> {typedef T type;};
+
+ template<class T>
+ typename remove_reference<T>::type&& move(T&& a) {
+ typedef typename remove_reference<T>::type&& RvalRef;
+ return static_cast<RvalRef>(a);
+ }
+
template<typename T>
class vector {
- typedef __iterator<T, T *, T &> iterator;
- typedef __iterator<T, const T *, const T &> const_iterator;
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __vector_iterator<T, T *, T &> iterator;
+ typedef __vector_iterator<T, const T *, const T &> const_iterator;
T *_start;
T *_finish;
T *_end_of_storage;
public:
vector() : _start(0), _finish(0), _end_of_storage(0) {}
+ template <typename InputIterator>
+ vector(InputIterator first, InputIterator last);
+ vector(const vector &other);
+ vector(vector &&other);
~vector();
size_t size() const {
return size_t(_finish - _start);
}
+
+ T &operator[](size_t n) {
+ return _start[n];
+ }
+
+ const T &operator[](size_t n) const {
+ return _start[n];
+ }
+
+ iterator begin() { return iterator(_start); }
+ const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
+ iterator end() { return iterator(_finish); }
+ const_iterator end() const { return const_iterator(_finish); }
+ const_iterator cend() const { return const_iterator(_finish); }
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ T& back() { return *(end() - 1); }
+ const T& back() const { return *(end() - 1); }
+ };
+
+ template<typename T>
+ class list {
+ struct __item {
+ T data;
+ __item *prev, *next;
+ } *_start, *_finish;
+ public:
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __list_iterator<__item, T *, T &> iterator;
+ typedef __list_iterator<__item, const T *, const T &> const_iterator;
+
+ list() : _start(0), _finish(0) {}
+ template <typename InputIterator>
+ list(InputIterator first, InputIterator last);
+ list(const list &other);
+ list(list &&other);
+ ~list();
- void push_back();
- T pop_back();
+ list& operator=(const list &other);
+ list& operator=(list &&other);
+ list& operator=(std::initializer_list<T> ilist);
+
+ iterator begin() { return iterator(_start); }
+ const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
+ iterator end() { return iterator(_finish); }
+ const_iterator end() const { return const_iterator(_finish); }
+ const_iterator cend() const { return const_iterator(_finish); }
+
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ T& back() { return *--end(); }
+ const T& back() const { return *--end(); }
+ };
+ template<typename T>
+ class deque {
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __deque_iterator<T, T *, T &> iterator;
+ typedef __deque_iterator<T, const T *, const T &> const_iterator;
+
+ T *_start;
+ T *_finish;
+ T *_end_of_storage;
+ public:
+ deque() : _start(0), _finish(0), _end_of_storage(0) {}
+ template <typename InputIterator>
+ deque(InputIterator first, InputIterator last);
+ deque(const deque &other);
+ deque(deque &&other);
+ ~deque();
+
+ size_t size() const {
+ return size_t(_finish - _start);
+ }
+
T &operator[](size_t n) {
return _start[n];
}
@@ -77,10 +340,46 @@ namespace std {
iterator begin() { return iterator(_start); }
const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
iterator end() { return iterator(_finish); }
const_iterator end() const { return const_iterator(_finish); }
+ const_iterator cend() const { return const_iterator(_finish); }
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ T& back() { return *(end() - 1); }
+ const T& back() const { return *(end() - 1); }
};
+ template<typename T>
+ class forward_list {
+ struct __item {
+ T data;
+ __item *next;
+ } *_start;
+ public:
+ typedef T value_type;
+ typedef size_t size_type;
+ typedef __fwdl_iterator<__item, T *, T &> iterator;
+ typedef __fwdl_iterator<__item, const T *, const T &> const_iterator;
+
+ forward_list() : _start(0) {}
+ template <typename InputIterator>
+ forward_list(InputIterator first, InputIterator last);
+ forward_list(const forward_list &other);
+ forward_list(forward_list &&other);
+ ~forward_list();
+
+ iterator begin() { return iterator(_start); }
+ const_iterator begin() const { return const_iterator(_start); }
+ const_iterator cbegin() const { return const_iterator(_start); }
+ iterator end() { return iterator(); }
+ const_iterator end() const { return const_iterator(); }
+ const_iterator cend() const { return const_iterator(); }
+
+ T& front() { return *begin(); }
+ const T& front() const { return *begin(); }
+ };
+
class exception {
public:
exception() throw();
@@ -247,41 +546,41 @@ namespace std {
OutputIter copy_backward(InputIter II, InputIter IE, OutputIter OI) {
return __copy_backward(II, IE, OI);
}
+}
+
+template <class BidirectionalIterator, class Distance>
+void __advance (BidirectionalIterator& it, Distance n,
+ std::bidirectional_iterator_tag) {
+ if (n >= 0) while(n-- > 0) ++it; else while (n++<0) --it;
+}
+
+template <class RandomAccessIterator, class Distance>
+void __advance (RandomAccessIterator& it, Distance n,
+ std::random_access_iterator_tag) {
+ it += n;
+}
+
+namespace std {
+ template <class InputIterator, class Distance>
+ void advance (InputIterator& it, Distance n) {
+ __advance(it, n, typename InputIterator::iterator_category());
+ }
+
+ template <class BidirectionalIterator>
+ BidirectionalIterator
+ prev (BidirectionalIterator it,
+ typename iterator_traits<BidirectionalIterator>::difference_type n =
+ 1) {
+ advance(it, -n);
+ return it;
+ }
template <class InputIterator, class T>
InputIterator find(InputIterator first, InputIterator last, const T &val);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 find_end(ForwardIterator1 first1, ForwardIterator1 last1,
- ForwardIterator2 first2, ForwardIterator2 last2);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 find_first_of(ForwardIterator1 first1,
- ForwardIterator1 last1,
- ForwardIterator2 first2,
- ForwardIterator2 last2);
- template <class InputIterator, class UnaryPredicate>
- InputIterator find_if(InputIterator first, InputIterator last,
- UnaryPredicate pred);
- template <class InputIterator, class UnaryPredicate>
- InputIterator find_if_not(InputIterator first, InputIterator last,
- UnaryPredicate pred);
- template <class InputIterator, class T>
- InputIterator lower_bound(InputIterator first, InputIterator last,
- const T &val);
- template <class InputIterator, class T>
- InputIterator upper_bound(InputIterator first, InputIterator last,
- const T &val);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 search(ForwardIterator1 first1, ForwardIterator1 last1,
- ForwardIterator2 first2, ForwardIterator2 last2);
- template <class ForwardIterator1, class ForwardIterator2>
- ForwardIterator1 search_n(ForwardIterator1 first1, ForwardIterator1 last1,
- ForwardIterator2 first2, ForwardIterator2 last2);
- struct input_iterator_tag { };
- struct output_iterator_tag { };
- struct forward_iterator_tag : public input_iterator_tag { };
- struct bidirectional_iterator_tag : public forward_iterator_tag { };
- struct random_access_iterator_tag : public bidirectional_iterator_tag { };
+ template <class InputIterator, class OutputIterator>
+ OutputIterator copy(InputIterator first, InputIterator last,
+ OutputIterator result);
}
diff --git a/test/Analysis/MismatchedDeallocator-path-notes.cpp b/test/Analysis/MismatchedDeallocator-path-notes.cpp
index 118f23bca1..1354386fc8 100644
--- a/test/Analysis/MismatchedDeallocator-path-notes.cpp
+++ b/test/Analysis/MismatchedDeallocator-path-notes.cpp
@@ -287,7 +287,7 @@ void test() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/MisusedMovedObject.cpp b/test/Analysis/MisusedMovedObject.cpp
new file mode 100644
index 0000000000..132a65de10
--- /dev/null
+++ b/test/Analysis/MisusedMovedObject.cpp
@@ -0,0 +1,675 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=alpha.cplusplus.MisusedMovedObject -std=c++11 -verify -analyzer-output=text %s
+
+namespace std {
+
+template <typename>
+struct remove_reference;
+
+template <typename _Tp>
+struct remove_reference { typedef _Tp type; };
+
+template <typename _Tp>
+struct remove_reference<_Tp &> { typedef _Tp type; };
+
+template <typename _Tp>
+struct remove_reference<_Tp &&> { typedef _Tp type; };
+
+template <typename _Tp>
+typename remove_reference<_Tp>::type &&move(_Tp &&__t) {
+ return static_cast<typename remove_reference<_Tp>::type &&>(__t);
+}
+
+template <typename _Tp>
+_Tp &&forward(typename remove_reference<_Tp>::type &__t) noexcept {
+ return static_cast<_Tp &&>(__t);
+}
+
+template <class T>
+void swap(T &a, T &b) {
+ T c(std::move(a));
+ a = std::move(b);
+ b = std::move(c);
+}
+
+} // namespace std
+
+class B {
+public:
+ B() = default;
+ B(const B &) = default;
+ B(B &&) = default;
+ B& operator=(const B &q) = default;
+ void operator=(B &&b) {
+ return;
+ }
+ void foo() { return; }
+};
+
+class A {
+ int i;
+ double d;
+
+public:
+ B b;
+ A(int ii = 42, double dd = 1.0) : d(dd), i(ii), b(B()) {}
+ void moveconstruct(A &&other) {
+ std::swap(b, other.b);
+ std::swap(d, other.d);
+ std::swap(i, other.i);
+ return;
+ }
+ static A get() {
+ A v(12, 13);
+ return v;
+ }
+ A(A *a) {
+ moveconstruct(std::move(*a));
+ }
+ A(const A &other) : i(other.i), d(other.d), b(other.b) {}
+ A(A &&other) : i(other.i), d(other.d), b(std::move(other.b)) { // expected-note {{'b' became 'moved-from' here}}
+ }
+ A(A &&other, char *k) {
+ moveconstruct(std::move(other));
+ }
+ void operator=(const A &other) {
+ i = other.i;
+ d = other.d;
+ b = other.b;
+ return;
+ }
+ void operator=(A &&other) {
+ moveconstruct(std::move(other));
+ return;
+ }
+ int getI() { return i; }
+ int foo() const;
+ void bar() const;
+ void reset();
+ void destroy();
+ void clear();
+ bool empty() const;
+ bool isEmpty() const;
+ operator bool() const;
+};
+
+int bignum();
+
+void moveInsideFunctionCall(A a) {
+ A b = std::move(a);
+}
+void leftRefCall(A &a) {
+ a.foo();
+}
+void rightRefCall(A &&a) {
+ a.foo();
+}
+void constCopyOrMoveCall(const A a) {
+ a.foo();
+}
+
+void copyOrMoveCall(A a) {
+ a.foo();
+}
+
+void simpleMoveCtorTest() {
+ {
+ A a;
+ A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ {
+ A a;
+ A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ b = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+ }
+ {
+ A a;
+ A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ b = std::move(a); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+ }
+}
+
+void simpleMoveAssignementTest() {
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ A c(a); // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ A c(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+ }
+}
+
+void moveInInitListTest() {
+ struct S {
+ A a;
+ };
+ A a;
+ S s{std::move(a)}; // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+// Don't report a bug if the variable was assigned to in the meantime.
+void reinitializationTest(int i) {
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ a = A();
+ a.foo();
+ }
+ {
+ A a;
+ if (i == 1) { // expected-note {{Assuming 'i' is not equal to 1}} expected-note {{Taking false branch}}
+ // expected-note@-1 {{Assuming 'i' is not equal to 1}} expected-note@-1 {{Taking false branch}}
+ A b;
+ b = std::move(a);
+ a = A();
+ }
+ if (i == 2) { // expected-note {{Assuming 'i' is not equal to 2}} expected-note {{Taking false branch}}
+ //expected-note@-1 {{Assuming 'i' is not equal to 2}} expected-note@-1 {{Taking false branch}}
+ a.foo(); // no-warning
+ }
+ }
+ {
+ A a;
+ if (i == 1) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
+ std::move(a);
+ }
+ if (i == 2) { // expected-note {{Taking false branch}} expected-note {{Taking false branch}}
+ a = A();
+ a.foo();
+ }
+ }
+ // The built-in assignment operator should also be recognized as a
+ // reinitialization. (std::move() may be called on built-in types in template
+ // code.)
+ {
+ int a1 = 1, a2 = 2;
+ std::swap(a1, a2);
+ }
+ // A std::move() after the assignment makes the variable invalid again.
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ a = A();
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ // If a path exist where we not reinitialize the variable we report a bug.
+ {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ if (i < 10) { // expected-note {{Assuming 'i' is >= 10}} expected-note {{Taking false branch}}
+ a = A();
+ }
+ if (i > 5) { // expected-note {{Taking true branch}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ }
+}
+
+// Using decltype on an expression is not a use.
+void decltypeIsNotUseTest() {
+ A a;
+ // A b(std::move(a));
+ decltype(a) other_a; // no-warning
+}
+
+void loopTest() {
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ rightRefCall(std::move(a)); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ rightRefCall(std::move(a)); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ leftRefCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ leftRefCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ constCopyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ constCopyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ moveInsideFunctionCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true. Entering loop body}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ moveInsideFunctionCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is false. Execution jumps to the end of the function}}
+ copyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < 2; i++) { // expected-note {{Loop condition is true.}}
+ //expected-note@-1 {{Loop condition is true. Entering loop body}}
+ //expected-note@-2 {{Loop condition is false. Execution jumps to the end of the function}}
+ copyOrMoveCall(a); // no-warning
+ }
+ }
+ {
+ A a;
+ for (int i = 0; i < bignum(); i++) { // expected-note {{Loop condition is true. Entering loop body}} expected-note {{Loop condition is true. Entering loop body}}
+ constCopyOrMoveCall(std::move(a)); // expected-warning {{Moving a 'moved-from' object 'a'}} expected-note {{Moving a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}}
+ }
+ }
+
+ // Don't warn if we return after the move.
+ {
+ A a;
+ for (int i = 0; i < 3; ++i) {
+ a.bar();
+ if (a.foo() > 0) {
+ A b;
+ b = std::move(a); // no-warning
+ return;
+ }
+ }
+ }
+}
+
+//report a usage of a moved-from object only at the first use
+void uniqueTest(bool cond) {
+ A a(42, 42.0);
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+
+ if (cond) { // expected-note {{Assuming 'cond' is not equal to 0}} expected-note {{Taking true branch}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ }
+ if (cond) {
+ a.bar(); // no-warning
+ }
+
+ a.bar(); // no-warning
+}
+
+void uniqueTest2() {
+ A a;
+ A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+
+ A a2 = std::move(a); // no-warning
+ a.foo(); // no-warning
+}
+
+// There are exceptions where we assume in general that the method works fine
+//even on moved-from objects.
+void moveSafeFunctionsTest() {
+ A a;
+ A b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.empty(); // no-warning
+ a.isEmpty(); // no-warning
+ (void)a; // no-warning
+ (bool)a; // expected-warning {{expression result unused}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+void moveStateResetFunctionsTest() {
+ {
+ A a;
+ A b = std::move(a);
+ a.reset(); // no-warning
+ a.foo(); // no-warning
+ // Test if resets the state of subregions as well.
+ a.b.foo(); // no-warning
+ }
+ {
+ A a;
+ A b = std::move(a);
+ a.destroy(); // no-warning
+ a.foo(); // no-warning
+ }
+ {
+ A a;
+ A b = std::move(a);
+ a.clear(); // no-warning
+ a.foo(); // no-warning
+ a.b.foo(); // no-warning
+ }
+}
+
+// Moves or uses that occur as part of template arguments.
+template <int>
+class ClassTemplate {
+public:
+ void foo(A a);
+};
+
+template <int>
+void functionTemplate(A a);
+
+void templateArgIsNotUseTest() {
+ {
+ // A pattern like this occurs in the EXPECT_EQ and ASSERT_EQ macros in
+ // Google Test.
+ A a;
+ ClassTemplate<sizeof(A(std::move(a)))>().foo(std::move(a)); // no-warning
+ }
+ {
+ A a;
+ functionTemplate<sizeof(A(std::move(a)))>(std::move(a)); // no-warning
+ }
+}
+
+// Moves of global variables are not reported.
+A global_a;
+void globalVariablesTest() {
+ std::move(global_a);
+ global_a.foo(); // no-warning
+}
+
+// Moves of member variables.
+class memberVariablesTest {
+ A a;
+ static A static_a;
+
+ void f() {
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
+
+ b = std::move(static_a); // expected-note {{'static_a' became 'moved-from' here}}
+ static_a.foo(); // expected-warning {{Method call on a 'moved-from' object 'static_a'}} expected-note {{Method call on a 'moved-from' object 'static_a'}}
+ }
+};
+
+void PtrAndArrayTest() {
+ A *Ptr = new A(1, 1.5);
+ A Arr[10];
+ Arr[2] = std::move(*Ptr); // expected-note {{Became 'moved-from' here}}
+ (*Ptr).foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
+
+ Ptr = &Arr[1];
+ Arr[3] = std::move(Arr[1]); // expected-note {{Became 'moved-from' here}}
+ Ptr->foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
+
+ Arr[3] = std::move(Arr[2]); // expected-note {{Became 'moved-from' here}}
+ Arr[2].foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object}}
+
+ Arr[2] = std::move(Arr[3]); // reinitialization
+ Arr[2].foo(); // no-warning
+}
+
+void exclusiveConditionsTest(bool cond) {
+ A a;
+ if (cond) {
+ A b;
+ b = std::move(a);
+ }
+ if (!cond) {
+ a.bar(); // no-warning
+ }
+}
+
+void differentBranchesTest(int i) {
+ // Don't warn if the use is in a different branch from the move.
+ {
+ A a;
+ if (i > 0) { // expected-note {{Assuming 'i' is > 0}} expected-note {{Taking true branch}}
+ A b;
+ b = std::move(a);
+ } else {
+ a.foo(); // no-warning
+ }
+ }
+ // Same thing, but with a ternary operator.
+ {
+ A a, b;
+ i > 0 ? (void)(b = std::move(a)) : a.bar(); // no-warning // expected-note {{'?' condition is true}}
+ }
+ // A variation on the theme above.
+ {
+ A a;
+ a.foo() > 0 ? a.foo() : A(std::move(a)).foo(); // expected-note {{Assuming the condition is false}} expected-note {{'?' condition is false}}
+ }
+ // Same thing, but with a switch statement.
+ {
+ A a, b;
+ switch (i) { // expected-note {{Control jumps to 'case 1:' at line 483}}
+ case 1:
+ b = std::move(a); // no-warning
+ break; // expected-note {{Execution jumps to the end of the function}}
+ case 2:
+ a.foo(); // no-warning
+ break;
+ }
+ }
+ // However, if there's a fallthrough, we do warn.
+ {
+ A a, b;
+ switch (i) { // expected-note {{Control jumps to 'case 1:' at line 495}}
+ case 1:
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ case 2:
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ break;
+ }
+ }
+}
+
+void tempTest() {
+ A a = A::get();
+ A::get().foo(); // no-warning
+ for (int i = 0; i < bignum(); i++) {
+ A::get().foo(); // no-warning
+ }
+}
+
+void interFunTest1(A &a) {
+ a.bar(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+}
+
+void interFunTest2() {
+ A a;
+ A b;
+ b = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ interFunTest1(a); // expected-note {{Calling 'interFunTest1'}}
+}
+
+void foobar(A a, int i);
+void foobar(int i, A a);
+
+void paramEvaluateOrderTest() {
+ A a;
+ foobar(std::move(a), a.getI()); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}}
+
+ //FALSE NEGATIVE since parameters evaluate order is undefined
+ foobar(a.getI(), std::move(a)); //no-warning
+}
+
+void not_known(A &a);
+void not_known(A *a);
+
+void regionAndPointerEscapeTest() {
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ not_known(a);
+ a.foo(); //no-warning
+ }
+ {
+ A a;
+ A b;
+ b = std::move(a);
+ not_known(&a);
+ a.foo(); // no-warning
+ }
+}
+
+// A declaration statement containing multiple declarations sequences the
+// initializer expressions.
+void declarationSequenceTest() {
+ {
+ A a;
+ A a1 = a, a2 = std::move(a); // no-warning
+ }
+ {
+ A a;
+ A a1 = std::move(a), a2 = a; // expected-warning {{Copying a 'moved-from' object 'a'}} expected-note {{Copying a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}}
+ }
+}
+
+// The logical operators && and || sequence their operands.
+void logicalOperatorsSequenceTest() {
+ {
+ A a;
+ if (a.foo() > 0 && A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
+ // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
+ //expected-note@-2 {{Taking false branch}} expected-note@-2 {{Taking false branch}}
+ A().bar();
+ }
+ }
+ // A variation: Negate the result of the && (which pushes the && further down
+ // into the AST).
+ {
+ A a;
+ if (!(a.foo() > 0 && A(std::move(a)).foo() > 0)) { // expected-note {{Assuming the condition is false}} expected-note {{Assuming the condition is false}}
+ // expected-note@-1 {{Left side of '&&' is false}} expected-note@-1 {{Left side of '&&' is false}}
+ // expected-note@-2 {{Taking true branch}} expected-note@-2 {{Taking true branch}}
+ A().bar();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).foo() > 0 && a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is true}} expected-note@-1 {{Assuming the condition is false}}
+ // expected-note@-2 {{Left side of '&&' is false}} expected-note@-2 {{Left side of '&&' is true}}
+ // expected-note@-3 {{Taking false branch}}
+ A().bar();
+ }
+ }
+ {
+ A a;
+ if (a.foo() > 0 || A(std::move(a)).foo() > 0) { // expected-note {{Assuming the condition is true}}
+ //expected-note@-1 {{Left side of '||' is true}}
+ //expected-note@-2 {{Taking true branch}}
+ A().bar();
+ }
+ }
+ {
+ A a;
+ if (A(std::move(a)).foo() > 0 || a.foo() > 0) { // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ // expected-note@-1 {{'a' became 'moved-from' here}} expected-note@-1 {{Assuming the condition is false}} expected-note@-1 {{Left side of '||' is false}}
+ A().bar();
+ }
+ }
+}
+
+// A range-based for sequences the loop variable declaration before the body.
+void forRangeSequencesTest() {
+ A v[2] = {A(), A()};
+ for (A &a : v) {
+ A b;
+ b = std::move(a); // no-warning
+ }
+}
+
+// If a variable is declared in an if statement, the declaration of the variable
+// (which is treated like a reinitialization by the check) is sequenced before
+// the evaluation of the condition (which constitutes a use).
+void ifStmtSequencesDeclAndConditionTest() {
+ for (int i = 0; i < 3; ++i) {
+ if (A a = A()) {
+ A b;
+ b = std::move(a); // no-warning
+ }
+ }
+}
+
+class C : public A {};
+void subRegionMoveTest() {
+ {
+ A a;
+ B b = std::move(a.b); // expected-note {{'b' became 'moved-from' here}}
+ a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
+ }
+ {
+ A a;
+ A a1 = std::move(a); // expected-note {{Calling move constructor for 'A'}} expected-note {{Returning from move constructor for 'A'}}
+ a.b.foo(); // expected-warning {{Method call on a 'moved-from' object 'b'}} expected-note {{Method call on a 'moved-from' object 'b'}}
+ }
+ // Don't report a misuse if any SuperRegion is already reported.
+ {
+ A a;
+ A a1 = std::move(a); // expected-note {{'a' became 'moved-from' here}}
+ a.foo(); // expected-warning {{Method call on a 'moved-from' object 'a'}} expected-note {{Method call on a 'moved-from' object 'a'}}
+ a.b.foo(); // no-warning
+ }
+ {
+ C c;
+ C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}}
+ c.foo(); // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}}
+ c.b.foo(); // no-warning
+ }
+}
+
+void resetSuperClass() {
+ C c;
+ C c1 = std::move(c);
+ c.clear();
+ C c2 = c; // no-warning
+}
+
+void reportSuperClass() {
+ C c;
+ C c1 = std::move(c); // expected-note {{'c' became 'moved-from' here}}
+ c.foo(); // expected-warning {{Method call on a 'moved-from' object 'c'}} expected-note {{Method call on a 'moved-from' object 'c'}}
+ C c2 = c; // no-warning
+}
diff --git a/test/Analysis/NewDelete-path-notes.cpp b/test/Analysis/NewDelete-path-notes.cpp
index 115a4addca..ac760ca60e 100644
--- a/test/Analysis/NewDelete-path-notes.cpp
+++ b/test/Analysis/NewDelete-path-notes.cpp
@@ -257,7 +257,7 @@ void test(Odd *odd) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Attempt to free released memory</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Double free</string>
// CHECK-NEXT: <key>check_name</key><string>cplusplus.NewDelete</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -475,7 +475,7 @@ void test(Odd *odd) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Attempt to free released memory</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Double free</string>
// CHECK-NEXT: <key>check_name</key><string>cplusplus.NewDelete</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/additive-folding.cpp b/test/Analysis/additive-folding.cpp
index 52056d472b..823b176004 100644
--- a/test/Analysis/additive-folding.cpp
+++ b/test/Analysis/additive-folding.cpp
@@ -205,3 +205,12 @@ void multiplicativeSanityTest(int x) {
clang_analyzer_eval(x == 3); // expected-warning{{UNKNOWN}}
}
+
+void additiveSymSymFolding(int x, int y) {
+ // We should simplify 'x - 1' to '0' and handle the comparison,
+ // despite both sides being complicated symbols.
+ int z = x - 1;
+ if (x == 1)
+ if (y >= 0)
+ clang_analyzer_eval(z <= y); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/analyzer-config.c b/test/Analysis/analyzer-config.c
index c0153a5053..4daea898ec 100644
--- a/test/Analysis/analyzer-config.c
+++ b/test/Analysis/analyzer-config.c
@@ -12,6 +12,9 @@ void foo() {
// CHECK: [config]
// CHECK-NEXT: cfg-conditional-static-initializers = true
+// CHECK-NEXT: cfg-implicit-dtors = true
+// CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -19,13 +22,13 @@ void foo() {
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: leak-diagnostics-reference-allocation = false
-// CHECK-NEXT: max-inlinable-size = 50
-// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-inlinable-size = 100
+// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 15
-
+// CHECK-NEXT: num-entries = 19
diff --git a/test/Analysis/analyzer-config.cpp b/test/Analysis/analyzer-config.cpp
index f84be17811..a08e85e53e 100644
--- a/test/Analysis/analyzer-config.cpp
+++ b/test/Analysis/analyzer-config.cpp
@@ -23,6 +23,9 @@ public:
// CHECK-NEXT: c++-stdlib-inlining = true
// CHECK-NEXT: c++-template-inlining = true
// CHECK-NEXT: cfg-conditional-static-initializers = true
+// CHECK-NEXT: cfg-implicit-dtors = true
+// CHECK-NEXT: cfg-lifetime = false
+// CHECK-NEXT: cfg-loopexit = false
// CHECK-NEXT: cfg-temporary-dtors = false
// CHECK-NEXT: faux-bodies = true
// CHECK-NEXT: graph-trim-interval = 1000
@@ -30,12 +33,13 @@ public:
// CHECK-NEXT: ipa = dynamic-bifurcate
// CHECK-NEXT: ipa-always-inline-size = 3
// CHECK-NEXT: leak-diagnostics-reference-allocation = false
-// CHECK-NEXT: max-inlinable-size = 50
-// CHECK-NEXT: max-nodes = 150000
+// CHECK-NEXT: max-inlinable-size = 100
+// CHECK-NEXT: max-nodes = 225000
// CHECK-NEXT: max-times-inline-large = 32
// CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
// CHECK-NEXT: mode = deep
// CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: unroll-loops = false
// CHECK-NEXT: widen-loops = false
// CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 20
+// CHECK-NEXT: num-entries = 24
diff --git a/test/Analysis/analyzer_test.py b/test/Analysis/analyzer_test.py
new file mode 100644
index 0000000000..0aa2dbc1bb
--- /dev/null
+++ b/test/Analysis/analyzer_test.py
@@ -0,0 +1,43 @@
+import lit.formats
+import lit.TestRunner
+
+# Custom format class for static analyzer tests
+class AnalyzerTest(lit.formats.ShTest):
+
+ def execute(self, test, litConfig):
+ results = []
+
+ # Parse any test requirements ('REQUIRES: ')
+ saved_test = test
+ lit.TestRunner.parseIntegratedTestScript(test)
+
+ if 'z3' not in test.requires:
+ results.append(self.executeWithAnalyzeSubstitution(
+ saved_test, litConfig, '-analyzer-constraints=range'))
+
+ if results[-1].code == lit.Test.FAIL:
+ return results[-1]
+
+ # If z3 backend available, add an additional run line for it
+ if test.config.clang_staticanalyzer_z3 == '1':
+ results.append(self.executeWithAnalyzeSubstitution(
+ saved_test, litConfig, '-analyzer-constraints=z3 -DANALYZER_CM_Z3'))
+
+ # Combine all result outputs into the last element
+ for x in results:
+ if x != results[-1]:
+ results[-1].output = x.output + results[-1].output
+
+ if results:
+ return results[-1]
+ return lit.Test.Result(lit.Test.UNSUPPORTED,
+ "Test requires the following unavailable features: z3")
+
+ def executeWithAnalyzeSubstitution(self, test, litConfig, substitution):
+ saved_substitutions = list(test.config.substitutions)
+ test.config.substitutions.append(('%analyze', substitution))
+ result = lit.TestRunner.executeShTest(test, litConfig,
+ self.execute_external)
+ test.config.substitutions = saved_substitutions
+
+ return result
diff --git a/test/Analysis/bitwise-ops.c b/test/Analysis/bitwise-ops.c
index 407aa19289..fe546580be 100644
--- a/test/Analysis/bitwise-ops.c
+++ b/test/Analysis/bitwise-ops.c
@@ -22,11 +22,32 @@ int testConstantShifts_PR18073(int which) {
case 1:
return 0ULL << 63; // no-warning
case 2:
- return 0ULL << 64; // expected-warning{{The result of the '<<' expression is undefined}}
+ return 0ULL << 64; // expected-warning{{The result of the left shift is undefined due to shifting by '64', which is greater or equal to the width of type 'unsigned long long'}}
case 3:
- return 0ULL << 65; // expected-warning{{The result of the '<<' expression is undefined}}
+ return 0ULL << 65; // expected-warning{{The result of the left shift is undefined due to shifting by '65', which is greater or equal to the width of type 'unsigned long long'}}
default:
return 0;
}
-} \ No newline at end of file
+}
+
+int testOverflowShift(int a) {
+ if (a == 323) {
+ return 1 << a; // expected-warning{{The result of the left shift is undefined due to shifting by '323', which is greater or equal to the width of type 'int'}}
+ }
+ return 0;
+}
+
+int testNegativeShift(int a) {
+ if (a == -5) {
+ return 1 << a; // expected-warning{{The result of the left shift is undefined because the right operand is negative}}
+ }
+ return 0;
+}
+
+int testNegativeLeftShift(int a) {
+ if (a == -3) {
+ return a << 1; // expected-warning{{The result of the left shift is undefined because the left operand is negative}}
+ }
+ return 0;
+}
diff --git a/test/Analysis/block-in-critical-section.cpp b/test/Analysis/block-in-critical-section.cpp
index c65cc612cf..fcf6188fc0 100644
--- a/test/Analysis/block-in-critical-section.cpp
+++ b/test/Analysis/block-in-critical-section.cpp
@@ -7,6 +7,20 @@ struct mutex {
void lock() {}
void unlock() {}
};
+template<typename T>
+struct lock_guard {
+ lock_guard<T>(std::mutex) {}
+ ~lock_guard<T>() {}
+};
+template<typename T>
+struct unique_lock {
+ unique_lock<T>(std::mutex) {}
+ ~unique_lock<T>() {}
+};
+template<typename T>
+struct not_real_lock {
+ not_real_lock<T>(std::mutex) {}
+};
}
void getc() {}
@@ -110,3 +124,31 @@ void testBlockInCriticalSectionUnexpectedUnlock() {
m.lock();
sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
}
+
+void testBlockInCriticalSectionLockGuard() {
+ std::mutex g_mutex;
+ std::not_real_lock<std::mutex> not_real_lock(g_mutex);
+ sleep(1); // no-warning
+
+ std::lock_guard<std::mutex> lock(g_mutex);
+ sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+}
+
+void testBlockInCriticalSectionLockGuardNested() {
+ testBlockInCriticalSectionLockGuard();
+ sleep(1); // no-warning
+}
+
+void testBlockInCriticalSectionUniqueLock() {
+ std::mutex g_mutex;
+ std::not_real_lock<std::mutex> not_real_lock(g_mutex);
+ sleep(1); // no-warning
+
+ std::unique_lock<std::mutex> lock(g_mutex);
+ sleep(1); // expected-warning {{Call to blocking function 'sleep' inside of critical section}}
+}
+
+void testBlockInCriticalSectionUniqueLockNested() {
+ testBlockInCriticalSectionUniqueLock();
+ sleep(1); // no-warning
+}
diff --git a/test/Analysis/block-in-critical-section.m b/test/Analysis/block-in-critical-section.m
new file mode 100644
index 0000000000..73d58479f4
--- /dev/null
+++ b/test/Analysis/block-in-critical-section.m
@@ -0,0 +1,10 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.unix.BlockInCriticalSection -verify -Wno-objc-root-class %s
+// expected-no-diagnostics
+
+@interface SomeClass
+-(void)someMethod;
+@end
+
+void shouldNotCrash(SomeClass *o) {
+ [o someMethod];
+}
diff --git a/test/Analysis/bstring.cpp b/test/Analysis/bstring.cpp
index a6d7b40162..fea76cc082 100644
--- a/test/Analysis/bstring.cpp
+++ b/test/Analysis/bstring.cpp
@@ -1,8 +1,35 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
+// RUN: %clang_analyze_cc1 -DUSE_BUILTINS -DVARIANT -analyzer-checker=core,unix.cstring,alpha.unix.cstring,debug.ExprInspection -analyzer-store=region -verify %s
#include "Inputs/system-header-simulator-cxx.h"
#include "Inputs/system-header-simulator-for-malloc.h"
+// This provides us with four possible mempcpy() definitions.
+// See also comments in bstring.c.
+
+#ifdef USE_BUILTINS
+#define BUILTIN(f) __builtin_##f
+#else /* USE_BUILTINS */
+#define BUILTIN(f) f
+#endif /* USE_BUILTINS */
+
+#ifdef VARIANT
+
+#define __mempcpy_chk BUILTIN(__mempcpy_chk)
+void *__mempcpy_chk(void *__restrict__ s1, const void *__restrict__ s2,
+ size_t n, size_t destlen);
+
+#define mempcpy(a,b,c) __mempcpy_chk(a,b,c,(size_t)-1)
+
+#else /* VARIANT */
+
+#define mempcpy BUILTIN(mempcpy)
+void *mempcpy(void *__restrict__ s1, const void *__restrict__ s2, size_t n);
+
+#endif /* VARIANT */
+
void clang_analyzer_eval(int);
int *testStdCopyInvalidatesBuffer(std::vector<int> v) {
@@ -36,3 +63,17 @@ int *testStdCopyBackwardInvalidatesBuffer(std::vector<int> v) {
return buf;
}
+
+namespace pr34460 {
+short a;
+class b {
+ int c;
+ long g;
+ void d() {
+ int e = c;
+ f += e;
+ mempcpy(f, &a, g);
+ }
+ unsigned *f;
+};
+}
diff --git a/test/Analysis/bug_hash_test.cpp b/test/Analysis/bug_hash_test.cpp
index 0efcb5f7cd..f397d181e6 100644
--- a/test/Analysis/bug_hash_test.cpp
+++ b/test/Analysis/bug_hash_test.cpp
@@ -1,1345 +1,122 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
-// RUN: FileCheck --input-file=%t.plist %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,debug.ExprInspection %s -verify
-int function(int p) {
- return 5;
+constexpr int clang_analyzer_hashDump(int) { return 5; }
+
+void function(int) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void function(int)$27$clang_analyzer_hashDump(5);$Category}}
}
namespace {
-int variadicParam(int p, ...) {
- return 5;
-}
+void variadicParam(int, ...) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void (anonymous namespace)::variadicParam(int, ...)$27$clang_analyzer_hashDump(5);$Category}}
}
+} // namespace
-constexpr int f() { return 5; }
+constexpr int f() {
+ return clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$int f()$34$returnclang_analyzer_hashDump(5);$Category}}
+}
namespace AA {
- class X {
- int priv;
- X() : priv(5) { priv = 0; }
+class X {
+ X() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::X()$29$clang_analyzer_hashDump(5);$Category}}
+ }
- static int static_method() {
- return 5;
- }
+ static void static_method() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::static_method()$29$clang_analyzer_hashDump(5);$Category}}
+ variadicParam(5);
+ }
- int method() && {
- class Y {
- inline int method() const & {
- return 5;
- }
- };
+ void method() && {
+ struct Y {
+ inline void method() const & {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::method()::Y::method() const &$33$clang_analyzer_hashDump(5);$Category}}
+ }
+ };
- return 5;
- }
+ Y y;
+ y.method();
- int OutOfLine();
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::method() &&$29$clang_analyzer_hashDump(5);$Category}}
+ }
- X& operator=(int a) {
- return *this;
- }
+ void OutOfLine();
- operator int() {
- return 0;
- }
+ X &operator=(int) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$class AA::X & AA::X::operator=(int)$29$clang_analyzer_hashDump(5);$Category}}
+ return *this;
+ }
- explicit operator float() {
- return 0;
- }
- };
-}
+ operator int() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::operator int()$29$clang_analyzer_hashDump(5);$Category}}
+ return 0;
+ }
-int AA::X::OutOfLine() {
- return 5;
+ explicit operator float() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$AA::X::operator float()$29$clang_analyzer_hashDump(5);$Category}}
+ return 0;
+ }
+};
+} // namespace AA
+
+void AA::X::OutOfLine() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void AA::X::OutOfLine()$27$clang_analyzer_hashDump(5);$Category}}
}
void testLambda() {
- [] () {
- return;
+ []() {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void testLambda()::(anonymous class)::operator()() const$29$clang_analyzer_hashDump(5);$Category}}
}();
}
-// CHECK: <key>diagnostics</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int function(int)$10$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int function(int)$10$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int function(int)$10$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>e7be204e83f8e5ad3c870ec011d5131d</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>function</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>5</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int (anonymous namespace)::variadicParam(int, ...)$10$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>bc5dc0507ee90f1d14259057d25fb2b9</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>variadicParam</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>10</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int f()$28$constexprintf(){return5;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f5471f52854dc14167fe96db50c4ba5f</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>f</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>14</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$16$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>d23266517ac17d5ec5e2fbbdb1922af1</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>7bfcc45512a6a3f61dda6e3ecebc7384</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$21$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>95dbfbcdd1dd6401d262994c45d088be</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>26</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>24</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::X()$28$X():priv(5){priv=0;}$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>064a01551caa8eca3202f1fd55b9c692</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>28</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int AA::X::static_method()$14$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>651fcca72f8ad65771702903ecd5f68a</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>static_method</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>22</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::method() &amp;&amp;$14$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::method() &amp;&amp;$14$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int AA::X::method() &amp;&amp;$14$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>c8ac8f24467234bea1f34adf5ad5007b</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>method</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>7</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>32</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$class AA::X &amp; AA::X::operator=(int)$14$return*this;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$class AA::X &amp; AA::X::operator=(int)$14$return*this;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$class AA::X &amp; AA::X::operator=(int)$14$return*this;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>b47cf7973c9b459d9c99c483e722db8e</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>operator=</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>38</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::operator int()$14$return0;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::operator int()$14$return0;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::operator int()$14$return0;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>0cbb0e1e5b03ba5b4f7f8f17504de671</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>42</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>12</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::operator float()$14$return0;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$AA::X::operator float()$14$return0;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$AA::X::operator float()$14$return0;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>df306826bf89e50c1b55e1d379a761b3</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>46</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$int AA::X::OutOfLine()$10$return5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>9dd7b17a6f62ed8c95b37a38cf71f3a9</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>C++ method</string>
-// CHECK-NEXT: <key>issue_context</key><string>OutOfLine</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>52</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>6ad4400e40885a78a0f57f585421a515</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testLambda</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testLambda()$3$[](){$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>6ad4400e40885a78a0f57f585421a515</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testLambda</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>56</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$4$}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testLambda()$4$}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testLambda()$4$}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>378e6de75fb41b05bcef3950ad5ffa5e</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testLambda</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>3</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>58</integer>
-// CHECK-NEXT: <key>col</key><integer>4</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
+template <typename T>
+void f(T) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(T)$27$clang_analyzer_hashDump(5);$Category}}
+}
+
+template <typename T>
+struct TX {
+ void f(T) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX::f(T)$29$clang_analyzer_hashDump(5);$Category}}
+ }
+};
+
+template <>
+void f<long>(long) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void f(long)$27$clang_analyzer_hashDump(5);$Category}}
+}
+
+template <>
+struct TX<long> {
+ void f(long) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TX<long>::f(long)$29$clang_analyzer_hashDump(5);$Category}}
+ }
+};
+
+template <typename T>
+struct TTX {
+ template<typename S>
+ void f(T, S) {
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$void TTX::f(T, S)$29$clang_analyzer_hashDump(5);$Category}}
+ }
+};
+
+void g() {
+ // TX<int> and TX<double> is instantiated from the same code with the same
+ // source locations. The same error happining in both of the instantiations
+ // should share the common hash. This means we should not include the
+ // template argument for these types in the function signature.
+ // Note that, we still want the hash to be different for explicit
+ // specializations.
+ TX<int> x;
+ TX<double> y;
+ TX<long> xl;
+ x.f(1);
+ xl.f(1);
+ f(5);
+ f(3.0);
+ y.f(2);
+ TTX<int> z;
+ z.f<int>(5, 5);
+ f(5l);
+}
diff --git a/test/Analysis/bug_hash_test.m b/test/Analysis/bug_hash_test.m
index 1e99d3c0b9..fbb70e5d62 100644
--- a/test/Analysis/bug_hash_test.m
+++ b/test/Analysis/bug_hash_test.m
@@ -1,5 +1,6 @@
-// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,debug.DumpBugHash -analyzer-output=plist %s -o %t.plist
-// RUN: FileCheck --input-file=%t.plist %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,debug.ExprInspection %s -verify
+
+void clang_analyzer_hashDump(int);
@protocol NSObject
+ (id)alloc;
@@ -15,1178 +16,21 @@ __attribute__((objc_root_class))
@end
@implementation NSObject
++ (id)alloc {
+ return 0;
+}
+- (id)init {
+ return self;
+}
- (void)method:(int)arg param:(int)arg2 {
- arg = 5;
- return;
+ clang_analyzer_hashDump(5); // expected-warning {{debug.ExprInspection$NSObject::method:param:$27$clang_analyzer_hashDump(5);$Category}}
}
@end
void testBlocks() {
int x = 5;
- ^{ int y = 1 + x; }();
+ ^{
+ clang_analyzer_hashDump(x); // expected-warning {{debug.ExprInspection$$29$clang_analyzer_hashDump(x);$Category}}
+ }();
}
-
-// CHECK: <key>diagnostics</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$NSObject::method:param:$3$arg=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f9f569e94382c1f969aabd304581b294</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>method:param:</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$NSObject::method:param:$9$arg=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>ca44d6aa882ee55f76e11a80d5a66372</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
-// CHECK-NEXT: <key>issue_context</key><string>method:param:</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>19</integer>
-// CHECK-NEXT: <key>col</key><integer>9</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>7</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$intx=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$intx=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$3$intx=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>84ec7c854c1c7849abfa03f7f20b4f06</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$11$intx=5;$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$11$intx=5;$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$11$intx=5;$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>f91db2d7b129ed60e7c9caf6f8a84d5c</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>11</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>21</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>0f1e9483a8ff59e787eaac18b68068ad</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>2</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$void testBlocks()$3$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>0f1e9483a8ff59e787eaac18b68068ad</string>
-// CHECK-NEXT: <key>issue_context_kind</key><string>function</string>
-// CHECK-NEXT: <key>issue_context</key><string>testBlocks</string>
-// CHECK-NEXT: <key>issue_hash_function_offset</key><string>2</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>10</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$6$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$6$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$6$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>8a8e42efc427e1334b77d510d3fb6361</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>6d6028808f1d47ec5b74a417e96c2a02</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>14</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$14$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>162138b23629276baad7dd3e8051fd6f</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>16</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>path</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>26</integer>
-// CHECK-NEXT: <key>col</key><integer>5</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>23</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>0</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Calling anonymous block</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>Entered call from &apos;testBlocks&apos;</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>3</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>control</string>
-// CHECK-NEXT: <key>edges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>start</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>6</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>8</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>end</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>kind</key><string>event</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <key>ranges</key>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <array>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>depth</key><integer>1</integer>
-// CHECK-NEXT: <key>extended_message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$18$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>message</key>
-// CHECK-NEXT: <string>debug.DumpBugHash$$18$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
-// CHECK-NEXT: <key>description</key><string>debug.DumpBugHash$$18$^{inty=1+x;}();$debug</string>
-// CHECK-NEXT: <key>category</key><string>debug</string>
-// CHECK-NEXT: <key>type</key><string>Dump hash components</string>
-// CHECK-NEXT: <key>check_name</key><string>debug.DumpBugHash</string>
-// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>b3add78bcab0ebc3da3b640081057525</string>
-// CHECK-NEXT: <key>location</key>
-// CHECK-NEXT: <dict>
-// CHECK-NEXT: <key>line</key><integer>27</integer>
-// CHECK-NEXT: <key>col</key><integer>18</integer>
-// CHECK-NEXT: <key>file</key><integer>0</integer>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </dict>
-// CHECK-NEXT: </array>
diff --git a/test/Analysis/builtin-functions.cpp b/test/Analysis/builtin-functions.cpp
index 4e9859754d..2c19502511 100644
--- a/test/Analysis/builtin-functions.cpp
+++ b/test/Analysis/builtin-functions.cpp
@@ -1,6 +1,7 @@
// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,debug.ExprInspection %s -std=c++11 -verify
void clang_analyzer_eval(bool);
+void clang_analyzer_warnIfReached();
void testAddressof(int x) {
clang_analyzer_eval(&x == __builtin_addressof(x)); // expected-warning{{TRUE}}
@@ -50,3 +51,16 @@ void test_assume_aligned_4(char *p) {
q = (char*) __builtin_assume_aligned(p + 1, 16);
clang_analyzer_eval(p == q); // expected-warning{{FALSE}}
}
+
+void f(int i) {
+ __builtin_assume(i < 10);
+ clang_analyzer_eval(i < 15); // expected-warning {{TRUE}}
+}
+
+void g(int i) {
+ if (i > 5) {
+ __builtin_assume(i < 5);
+ clang_analyzer_warnIfReached(); // Assumtion contradicts constraints.
+ // We give up the analysis on this path.
+ }
+}
diff --git a/test/Analysis/call_once.cpp b/test/Analysis/call_once.cpp
new file mode 100644
index 0000000000..5013cd423e
--- /dev/null
+++ b/test/Analysis/call_once.cpp
@@ -0,0 +1,305 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -fblocks -analyzer-checker=core,debug.ExprInspection -DEMULATE_LIBSTDCPP -verify %s
+
+void clang_analyzer_eval(bool);
+
+// Faking std::std::call_once implementation.
+namespace std {
+
+#ifndef EMULATE_LIBSTDCPP
+typedef struct once_flag_s {
+ unsigned long __state_ = 0;
+} once_flag;
+#else
+typedef struct once_flag_s {
+ int _M_once = 0;
+} once_flag;
+#endif
+
+template <class Callable, class... Args>
+void call_once(once_flag &o, Callable&& func, Args&&... args) {};
+
+} // namespace std
+
+// Check with Lambdas.
+void test_called_warning() {
+ std::once_flag g_initialize;
+ int z;
+
+ std::call_once(g_initialize, [&] {
+ int *x = nullptr;
+ int y = *x; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+ z = 200;
+ });
+}
+
+void test_called_on_path_inside_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+ int z;
+
+ std::call_once(g_initialize, [&] {
+ z = 200;
+ x = &z;
+ });
+
+ *x = 100; // no-warning
+ clang_analyzer_eval(z == 100); // expected-warning{{TRUE}}
+}
+
+void test_called_on_path_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+ *x = 100; // no-warning
+}
+
+void test_called_on_path_warning() {
+ std::once_flag g_initialize;
+
+ int y = 100;
+ int *x = &y;
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+ *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+}
+
+void test_called_once_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+ *x = 100; // expected-warning{{Dereference of null pointer (loaded from variable 'x')}}
+}
+
+void test_called_once_no_warning() {
+ std::once_flag g_initialize;
+
+ int *x = nullptr;
+ int y = 100;
+
+ std::call_once(g_initialize, [&] {
+ x = &y;
+ });
+
+ std::call_once(g_initialize, [&] {
+ x = nullptr;
+ });
+
+ *x = 100; // no-warning
+}
+
+static int global = 0;
+void funcPointer() {
+ global = 1;
+}
+
+void test_func_pointers() {
+ static std::once_flag flag;
+ std::call_once(flag, &funcPointer);
+ clang_analyzer_eval(global == 1); // expected-warning{{TRUE}}
+}
+
+template <class _Fp>
+class function; // undefined
+template <class _Rp, class... _ArgTypes>
+struct function<_Rp(_ArgTypes...)> {
+ _Rp operator()(_ArgTypes...) const {};
+ template <class _Fp>
+ function(_Fp) {};
+};
+
+// Note: currently we do not support calls to std::function,
+// but the analyzer should not crash either.
+void test_function_objects_warning() {
+ int x = 0;
+ int *y = &x;
+
+ std::once_flag flag;
+
+ function<void()> func = [&]() {
+ y = nullptr;
+ };
+
+ std::call_once(flag, func);
+
+ func();
+ int z = *y;
+}
+
+void test_param_passing_lambda() {
+ std::once_flag flag;
+ int x = 120;
+ int y = 0;
+
+ std::call_once(flag, [&](int p) {
+ y = p;
+ },
+ x);
+
+ clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
+}
+
+void test_param_passing_lambda_false() {
+ std::once_flag flag;
+ int x = 120;
+
+ std::call_once(flag, [&](int p) {
+ x = 0;
+ },
+ x);
+
+ clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
+}
+
+void test_param_passing_stored_lambda() {
+ std::once_flag flag;
+ int x = 120;
+ int y = 0;
+
+ auto lambda = [&](int p) {
+ y = p;
+ };
+
+ std::call_once(flag, lambda, x);
+ clang_analyzer_eval(y == 120); // expected-warning{{TRUE}}
+}
+
+void test_multiparam_passing_lambda() {
+ std::once_flag flag;
+ int x = 120;
+
+ std::call_once(flag, [&](int a, int b, int c) {
+ x = a + b + c;
+ },
+ 1, 2, 3);
+
+ clang_analyzer_eval(x == 120); // expected-warning{{FALSE}}
+ clang_analyzer_eval(x == 6); // expected-warning{{TRUE}}
+}
+
+static int global2 = 0;
+void test_param_passing_lambda_global() {
+ std::once_flag flag;
+ global2 = 0;
+ std::call_once(flag, [&](int a, int b, int c) {
+ global2 = a + b + c;
+ },
+ 1, 2, 3);
+ clang_analyzer_eval(global2 == 6); // expected-warning{{TRUE}}
+}
+
+static int global3 = 0;
+void funcptr(int a, int b, int c) {
+ global3 = a + b + c;
+}
+
+void test_param_passing_funcptr() {
+ std::once_flag flag;
+ global3 = 0;
+
+ std::call_once(flag, &funcptr, 1, 2, 3);
+
+ clang_analyzer_eval(global3 == 6); // expected-warning{{TRUE}}
+}
+
+void test_blocks() {
+ global3 = 0;
+ std::once_flag flag;
+ std::call_once(flag, ^{
+ global3 = 120;
+ });
+ clang_analyzer_eval(global3 == 120); // expected-warning{{TRUE}}
+}
+
+int call_once() {
+ return 5;
+}
+
+void test_non_std_call_once() {
+ int x = call_once();
+ clang_analyzer_eval(x == 5); // expected-warning{{TRUE}}
+}
+
+namespace std {
+template <typename d, typename e>
+void call_once(d, e);
+}
+void g();
+void test_no_segfault_on_different_impl() {
+ std::call_once(g, false); // no-warning
+}
+
+void test_lambda_refcapture() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [&](int &a) { a = 42; }, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+}
+
+void test_lambda_refcapture2() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [=](int &a) { a = 42; }, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+}
+
+void test_lambda_fail_refcapture() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, [=](int a) { a = 42; }, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
+}
+
+void mutator(int &param) {
+ param = 42;
+}
+void test_reftypes_funcptr() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, &mutator, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{TRUE}}
+}
+
+void fail_mutator(int param) {
+ param = 42;
+}
+void test_mutator_noref() {
+ static std::once_flag flag;
+ int a = 6;
+ std::call_once(flag, &fail_mutator, a);
+ clang_analyzer_eval(a == 42); // expected-warning{{FALSE}}
+}
+
+// Function is implicitly treated as a function pointer
+// even when an ampersand is not explicitly set.
+void callbackn(int &param) {
+ param = 42;
+}
+void test_implicit_funcptr() {
+ int x = 0;
+ static std::once_flag flagn;
+
+ std::call_once(flagn, callbackn, x);
+ clang_analyzer_eval(x == 42); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/casts.c b/test/Analysis/casts.c
index 92082fec2b..24bba8a30a 100644
--- a/test/Analysis/casts.c
+++ b/test/Analysis/casts.c
@@ -118,3 +118,34 @@ void castsToBool() {
extern float globalFloat;
clang_analyzer_eval(globalFloat); // expected-warning{{UNKNOWN}}
}
+
+void locAsIntegerCasts(void *p) {
+ int x = (int) p;
+ clang_analyzer_eval(++x < 10); // no-crash // expected-warning{{UNKNOWN}}
+}
+
+void multiDimensionalArrayPointerCasts() {
+ static int x[10][10];
+ int *y1 = &(x[3][5]);
+ char *z = ((char *) y1) + 2;
+ int *y2 = (int *)(z - 2);
+ int *y3 = ((int *)x) + 35; // This is offset for [3][5].
+
+ clang_analyzer_eval(y1 == y2); // expected-warning{{TRUE}}
+
+ // FIXME: should be FALSE (i.e. equal pointers).
+ clang_analyzer_eval(y1 - y2); // expected-warning{{UNKNOWN}}
+ // FIXME: should be TRUE (i.e. same symbol).
+ clang_analyzer_eval(*y1 == *y2); // expected-warning{{UNKNOWN}}
+
+ clang_analyzer_eval(*((char *)y1) == *((char *) y2)); // expected-warning{{TRUE}}
+
+ clang_analyzer_eval(y1 == y3); // expected-warning{{TRUE}}
+
+ // FIXME: should be FALSE (i.e. equal pointers).
+ clang_analyzer_eval(y1 - y3); // expected-warning{{UNKNOWN}}
+ // FIXME: should be TRUE (i.e. same symbol).
+ clang_analyzer_eval(*y1 == *y3); // expected-warning{{UNKNOWN}}
+
+ clang_analyzer_eval(*((char *)y1) == *((char *) y3)); // expected-warning{{TRUE}}
+}
diff --git a/test/Analysis/compound-literals.c b/test/Analysis/compound-literals.c
new file mode 100644
index 0000000000..a2556d2a79
--- /dev/null
+++ b/test/Analysis/compound-literals.c
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -triple=i386-apple-darwin10 -analyze -analyzer-checker=debug.ExprInspection -verify %s
+void clang_analyzer_eval(int);
+
+// pr28449: Used to crash.
+void foo(void) {
+ static const unsigned short array[] = (const unsigned short[]){0x0F00};
+ // FIXME: Should be true.
+ clang_analyzer_eval(array[0] == 0x0F00); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/conversion.c b/test/Analysis/conversion.c
index 5827794af2..7adb336eb2 100644
--- a/test/Analysis/conversion.c
+++ b/test/Analysis/conversion.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -Wno-conversion -analyzer-checker=core,alpha.core.Conversion -verify %s
+// RUN: %clang_analyze_cc1 -Wno-conversion -Wno-tautological-constant-compare -analyzer-checker=core,alpha.core.Conversion -verify %s
unsigned char U8;
signed char S8;
@@ -9,9 +9,67 @@ void assign(unsigned U, signed S) {
if (U > 300)
S8 = U; // expected-warning {{Loss of precision in implicit conversion}}
if (S > 10)
- U8 = S;
+ U8 = S; // no-warning
if (U < 200)
- S8 = U;
+ S8 = U; // no-warning
+}
+
+void addAssign() {
+ unsigned long L = 1000;
+ int I = -100;
+ U8 += L; // expected-warning {{Loss of precision in implicit conversion}}
+ L += I; // no-warning
+}
+
+void subAssign() {
+ unsigned long L = 1000;
+ int I = -100;
+ U8 -= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L -= I; // no-warning
+}
+
+void mulAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 *= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L *= I; // expected-warning {{Loss of sign in implicit conversion}}
+ I = 10;
+ L *= I; // no-warning
+}
+
+void divAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 /= L; // no-warning
+ L /= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void remAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 %= L; // no-warning
+ L %= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void andAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 &= L; // no-warning
+ L &= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void orAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 |= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L |= I; // expected-warning {{Loss of sign in implicit conversion}}
+}
+
+void xorAssign() {
+ unsigned long L = 1000;
+ int I = -1;
+ U8 ^= L; // expected-warning {{Loss of precision in implicit conversion}}
+ L ^= I; // expected-warning {{Loss of sign in implicit conversion}}
}
void init1() {
@@ -21,7 +79,7 @@ void init1() {
void relational(unsigned U, signed S) {
if (S > 10) {
- if (U < S) {
+ if (U < S) { // no-warning
}
}
if (S < -10) {
@@ -32,14 +90,14 @@ void relational(unsigned U, signed S) {
void multiplication(unsigned U, signed S) {
if (S > 5)
- S = U * S;
+ S = U * S; // no-warning
if (S < -10)
S = U * S; // expected-warning {{Loss of sign}}
}
void division(unsigned U, signed S) {
if (S > 5)
- S = U / S;
+ S = U / S; // no-warning
if (S < -10)
S = U / S; // expected-warning {{Loss of sign}}
}
diff --git a/test/Analysis/copypaste/asm.cpp b/test/Analysis/copypaste/asm.cpp
index 2e3613dfca..1d93469aa3 100644
--- a/test/Analysis/copypaste/asm.cpp
+++ b/test/Analysis/copypaste/asm.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-linux -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/attributes.cpp b/test/Analysis/copypaste/attributes.cpp
index 083be74436..f71545130c 100644
--- a/test/Analysis/copypaste/attributes.cpp
+++ b/test/Analysis/copypaste/attributes.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/autogenerated_automoc.cpp b/test/Analysis/copypaste/autogenerated_automoc.cpp
new file mode 100644
index 0000000000..0f7f9c9e45
--- /dev/null
+++ b/test/Analysis/copypaste/autogenerated_automoc.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|.*_automoc.cpp" -verify %s
+
+// Because files that have `_automoc.' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/blocks.cpp b/test/Analysis/copypaste/blocks.cpp
index 10467b7248..23821560ea 100644
--- a/test/Analysis/copypaste/blocks.cpp
+++ b/test/Analysis/copypaste/blocks.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -fblocks -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// This tests if we search for clones in blocks.
diff --git a/test/Analysis/copypaste/call.cpp b/test/Analysis/copypaste/call.cpp
index 046229a30a..c5ddae5a65 100644
--- a/test/Analysis/copypaste/call.cpp
+++ b/test/Analysis/copypaste/call.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/catch.cpp b/test/Analysis/copypaste/catch.cpp
index cf3e8076bd..edcf44ae6f 100644
--- a/test/Analysis/copypaste/catch.cpp
+++ b/test/Analysis/copypaste/catch.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/dbus_autogenerated.cpp b/test/Analysis/copypaste/dbus_autogenerated.cpp
new file mode 100644
index 0000000000..1824375658
--- /dev/null
+++ b/test/Analysis/copypaste/dbus_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|dbus_|.*_automoc" -verify %s
+
+// Because files that have `dbus_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/delete.cpp b/test/Analysis/copypaste/delete.cpp
index 394226bedf..4edb46035a 100644
--- a/test/Analysis/copypaste/delete.cpp
+++ b/test/Analysis/copypaste/delete.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/dependent-exist.cpp b/test/Analysis/copypaste/dependent-exist.cpp
index 9046353d0f..28f2ceb21a 100644
--- a/test/Analysis/copypaste/dependent-exist.cpp
+++ b/test/Analysis/copypaste/dependent-exist.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -fms-extensions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fms-extensions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/expr-types.cpp b/test/Analysis/copypaste/expr-types.cpp
index 601f0b192a..6062be306e 100644
--- a/test/Analysis/copypaste/expr-types.cpp
+++ b/test/Analysis/copypaste/expr-types.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/fold.cpp b/test/Analysis/copypaste/fold.cpp
index 0aed11bcf0..fadcb49fa0 100644
--- a/test/Analysis/copypaste/fold.cpp
+++ b/test/Analysis/copypaste/fold.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/function-try-block.cpp b/test/Analysis/copypaste/function-try-block.cpp
index d77714591b..d0fbc50f67 100644
--- a/test/Analysis/copypaste/function-try-block.cpp
+++ b/test/Analysis/copypaste/function-try-block.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -fcxx-exceptions -std=c++1z -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// Tests if function try blocks are correctly handled.
diff --git a/test/Analysis/copypaste/functions.cpp b/test/Analysis/copypaste/functions.cpp
index d2c607b217..2bfe591a50 100644
--- a/test/Analysis/copypaste/functions.cpp
+++ b/test/Analysis/copypaste/functions.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// This tests if we search for clones in functions.
diff --git a/test/Analysis/copypaste/generic.c b/test/Analysis/copypaste/generic.c
index d4d4564736..2fa6c302da 100644
--- a/test/Analysis/copypaste/generic.c
+++ b/test/Analysis/copypaste/generic.c
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/labels.cpp b/test/Analysis/copypaste/labels.cpp
index eff3330a0f..18c5b22d3b 100644
--- a/test/Analysis/copypaste/labels.cpp
+++ b/test/Analysis/copypaste/labels.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=gnu++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=gnu++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/lambda.cpp b/test/Analysis/copypaste/lambda.cpp
index 17c8748943..456d83a995 100644
--- a/test/Analysis/copypaste/lambda.cpp
+++ b/test/Analysis/copypaste/lambda.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// expected-no-diagnostics
diff --git a/test/Analysis/copypaste/macros.cpp b/test/Analysis/copypaste/macros.cpp
index bdacd4839a..ea05bbd428 100644
--- a/test/Analysis/copypaste/macros.cpp
+++ b/test/Analysis/copypaste/macros.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// Tests that macros and non-macro clones aren't mixed into the same hash
// group. This is currently necessary as all clones in a hash group need
diff --git a/test/Analysis/copypaste/moc_autogenerated.cpp b/test/Analysis/copypaste/moc_autogenerated.cpp
new file mode 100644
index 0000000000..626fe2a3dd
--- /dev/null
+++ b/test/Analysis/copypaste/moc_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|.*_automoc" -verify %s
+
+// Because files that have `moc_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/not-autogenerated.cpp b/test/Analysis/copypaste/not-autogenerated.cpp
new file mode 100644
index 0000000000..d54ee176fa
--- /dev/null
+++ b/test/Analysis/copypaste/not-autogenerated.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|ui_|dbus_|.*_automoc" -verify %s
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1; // expected-note{{Similar code using 'p1' here}}
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // expected-warning{{Potential copy-paste error; did you really mean to use 'p1' here?}}
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/copypaste/objc-methods.m b/test/Analysis/copypaste/objc-methods.m
index e63c7f6288..0a84370793 100644
--- a/test/Analysis/copypaste/objc-methods.m
+++ b/test/Analysis/copypaste/objc-methods.m
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -Wno-objc-root-class -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -Wno-objc-root-class -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// This tests if we search for clones in Objective-C methods.
diff --git a/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp b/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp
index 7c4f35525f..d4402a9dd5 100644
--- a/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp
+++ b/test/Analysis/copypaste/plist-diagnostics-notes-as-events.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-output=plist -analyzer-config notes-as-events=true -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=plist -analyzer-config notes-as-events=true -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// RUN: FileCheck --input-file=%t.plist %s
void log();
diff --git a/test/Analysis/copypaste/plist-diagnostics.cpp b/test/Analysis/copypaste/plist-diagnostics.cpp
index e2fa7597ca..c138c6f1f9 100644
--- a/test/Analysis/copypaste/plist-diagnostics.cpp
+++ b/test/Analysis/copypaste/plist-diagnostics.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=plist -o %t.plist -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// RUN: FileCheck --input-file=%t.plist %s
void log();
diff --git a/test/Analysis/copypaste/sub-sequences.cpp b/test/Analysis/copypaste/sub-sequences.cpp
index 798662d256..d2c08350ab 100644
--- a/test/Analysis/copypaste/sub-sequences.cpp
+++ b/test/Analysis/copypaste/sub-sequences.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// This tests if sub-sequences can match with normal sequences.
diff --git a/test/Analysis/copypaste/suspicious-clones.cpp b/test/Analysis/copypaste/suspicious-clones.cpp
index 3a760e2562..ae29b0e16d 100644
--- a/test/Analysis/copypaste/suspicious-clones.cpp
+++ b/test/Analysis/copypaste/suspicious-clones.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:ReportSuspiciousClones=true -analyzer-config alpha.clone.CloneChecker:ReportNormalClones=false -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:ReportSuspiciousClones=true -analyzer-config alpha.clone.CloneChecker:ReportNormalClones=false -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
// Tests finding a suspicious clone that references local variables.
diff --git a/test/Analysis/copypaste/text-diagnostics.cpp b/test/Analysis/copypaste/text-diagnostics.cpp
index a6e358cc85..a3132e9534 100644
--- a/test/Analysis/copypaste/text-diagnostics.cpp
+++ b/test/Analysis/copypaste/text-diagnostics.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_analyze_cc1 -analyzer-output=text -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-output=text -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:MinimumCloneComplexity=10 -verify %s
void log();
diff --git a/test/Analysis/copypaste/ui_autogenerated.cpp b/test/Analysis/copypaste/ui_autogenerated.cpp
new file mode 100644
index 0000000000..a08c33fe9e
--- /dev/null
+++ b/test/Analysis/copypaste/ui_autogenerated.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=alpha.clone.CloneChecker -analyzer-config alpha.clone.CloneChecker:IgnoredFilesPattern="moc_|ui_|.*_automoc" -verify %s
+
+// Because files that have `ui_' in their names are most likely autogenerated,
+// we suppress copy-paste warnings here.
+
+// expected-no-diagnostics
+
+void f1() {
+ int *p1 = new int[1];
+ int *p2 = new int[1];
+ if (p1) {
+ delete [] p1;
+ p1 = nullptr;
+ }
+ if (p2) {
+ delete [] p1; // no-warning
+ p2 = nullptr;
+ }
+}
diff --git a/test/Analysis/ctor.mm b/test/Analysis/ctor.mm
index 646229aac9..e903263431 100644
--- a/test/Analysis/ctor.mm
+++ b/test/Analysis/ctor.mm
@@ -199,7 +199,7 @@ namespace PODUninitialized {
Inner p;
};
- void testPOD() {
+ void testPOD(const POD &pp) {
POD p;
p.x = 1;
POD p2 = p; // no-warning
@@ -210,6 +210,15 @@ namespace PODUninitialized {
// Use rvalues as well.
clang_analyzer_eval(POD(p3).x == 1); // expected-warning{{TRUE}}
+ // Copy from symbolic references correctly.
+ POD p4 = pp;
+ // Make sure that p4.x contains a symbol after copy.
+ if (p4.x > 0)
+ clang_analyzer_eval(p4.x > 0); // expected-warning{{TRUE}}
+ // FIXME: Element region gets in the way, so these aren't the same symbols
+ // as they should be.
+ clang_analyzer_eval(pp.x == p4.x); // expected-warning{{UNKNOWN}}
+
PODWrapper w;
w.p.y = 1;
PODWrapper w2 = w; // no-warning
@@ -704,3 +713,20 @@ namespace PR19579 {
};
}
}
+
+namespace NoCrashOnEmptyBaseOptimization {
+ struct NonEmptyBase {
+ int X;
+ explicit NonEmptyBase(int X) : X(X) {}
+ };
+
+ struct EmptyBase {};
+
+ struct S : NonEmptyBase, EmptyBase {
+ S() : NonEmptyBase(0), EmptyBase() {}
+ };
+
+ void testSCtorNoCrash() {
+ S s;
+ }
+}
diff --git a/test/Analysis/diagnostics/diag-cross-file-boundaries.c b/test/Analysis/diagnostics/diag-cross-file-boundaries.c
deleted file mode 100644
index b975af3fb2..0000000000
--- a/test/Analysis/diagnostics/diag-cross-file-boundaries.c
+++ /dev/null
@@ -1,12 +0,0 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=html -o PR12421.html %s 2>&1 | FileCheck %s
-
-// Test for PR12421
-#include "diag-cross-file-boundaries.h"
-
-int main(){
- f();
- return 0;
-}
-
-// CHECK: warning: Path diagnostic report is not generated.
diff --git a/test/Analysis/diagnostics/explicit-suppression.cpp b/test/Analysis/diagnostics/explicit-suppression.cpp
index 193846c082..96d2b4a7d0 100644
--- a/test/Analysis/diagnostics/explicit-suppression.cpp
+++ b/test/Analysis/diagnostics/explicit-suppression.cpp
@@ -19,6 +19,6 @@ class C {
void testCopyNull(C *I, C *E) {
std::copy(I, E, (C *)0);
#ifndef SUPPRESSED
- // expected-warning@../Inputs/system-header-simulator-cxx.h:191 {{Called C++ object pointer is null}}
+ // expected-warning@../Inputs/system-header-simulator-cxx.h:490 {{Called C++ object pointer is null}}
#endif
}
diff --git a/test/Analysis/diagnostics/report-issues-within-main-file.cpp b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
index 784fdba972..e1dccc8e32 100644
--- a/test/Analysis/diagnostics/report-issues-within-main-file.cpp
+++ b/test/Analysis/diagnostics/report-issues-within-main-file.cpp
@@ -945,7 +945,7 @@ void callInMacroArg() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos; (within a call to &apos;~auto_ptr&apos;)</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/edges-new.mm b/test/Analysis/edges-new.mm
index 217cd4aa46..f310f1bfa1 100644
--- a/test/Analysis/edges-new.mm
+++ b/test/Analysis/edges-new.mm
@@ -20042,7 +20042,7 @@ namespace rdar14960554 {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -20284,11 +20284,11 @@ namespace rdar14960554 {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by &apos;new[]&apos; should be deallocated by &apos;delete[]&apos;, not &apos;delete&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
-// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>d9dbbf68db41ab74e2158f4b131abe34</string>
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>046c88d1c91ff46d6506dff5ff880756</string>
// CHECK-NEXT: <key>issue_hash_function_offset</key><string>0</string>
// CHECK-NEXT: <key>location</key>
// CHECK-NEXT: <dict>
diff --git a/test/Analysis/enum.cpp b/test/Analysis/enum.cpp
index e26b8f00d9..96408473ce 100644
--- a/test/Analysis/enum.cpp
+++ b/test/Analysis/enum.cpp
@@ -24,3 +24,46 @@ void testCasting(int i) {
clang_analyzer_eval(j == 0); // expected-warning{{FALSE}}
}
}
+
+enum class EnumBool : bool {
+ F = false,
+ T = true
+};
+
+bool testNoCrashOnSwitchEnumBool(EnumBool E) {
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
+
+bool testNoCrashOnSwitchEnumBoolConstant() {
+ EnumBool E = EnumBool::F;
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
+
+typedef __INTPTR_TYPE__ intptr_t;
+bool testNoCrashOnSwitchEnumBoolConstantCastedFromNullptr() {
+ EnumBool E = static_cast<EnumBool>((intptr_t)nullptr);
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
+
+bool testNoCrashOnSwitchEnumBoolConstantCastedFromPtr() {
+ int X;
+ intptr_t P = (intptr_t)&X;
+ EnumBool E = static_cast<EnumBool>(P);
+ switch (E) {
+ case EnumBool::F:
+ return false;
+ }
+ return true;
+}
diff --git a/test/Analysis/exercise-ps.c b/test/Analysis/exercise-ps.c
index 577b88bf83..c459260c2a 100644
--- a/test/Analysis/exercise-ps.c
+++ b/test/Analysis/exercise-ps.c
@@ -21,3 +21,11 @@ static void f2(void *buf) {
memcpy((&x[1]), (buf), 1); // expected-warning{{implicitly declaring library function 'memcpy' with type 'void *(void *, const void *}} \
// expected-note{{include the header <string.h> or explicitly provide a declaration for 'memcpy'}}
}
+
+// AllocaRegion is untyped. Void pointer isn't of much help either. Before
+// realizing that the value is undefined, we need to somehow figure out
+// what type of value do we expect.
+void f3(void *dest) {
+ void *src = __builtin_alloca(5);
+ memcpy(dest, src, 1); // expected-warning{{2nd function call argument is a pointer to uninitialized value}}
+}
diff --git a/test/Analysis/expr-inspection.c b/test/Analysis/expr-inspection.c
index 1e21efb4ef..ec0e682b65 100644
--- a/test/Analysis/expr-inspection.c
+++ b/test/Analysis/expr-inspection.c
@@ -8,6 +8,7 @@ void clang_analyzer_numTimesReached();
void foo(int x) {
clang_analyzer_dump(x); // expected-warning{{reg_$0<int x>}}
+ clang_analyzer_dump(x + (-1)); // expected-warning{{(reg_$0<int x>) + -1}}
int y = 1;
clang_analyzer_printState();
for (; y < 3; ++y)
@@ -19,4 +20,4 @@ void foo(int x) {
// CHECK: Expressions:
// CHECK-NEXT: clang_analyzer_printState : &code{clang_analyzer_printState}
-// CHECK-NEXT: Ranges are empty.
+// CHECK-NEXT: {{(Ranges are empty.)|(Constraints:[[:space:]]*$)}}
diff --git a/test/Analysis/func-mapping-test.cpp b/test/Analysis/func-mapping-test.cpp
new file mode 100644
index 0000000000..37e653882b
--- /dev/null
+++ b/test/Analysis/func-mapping-test.cpp
@@ -0,0 +1,7 @@
+// RUN: %clang_func_map %s -- | FileCheck %s
+
+int f(int) {
+ return 0;
+}
+
+// CHECK: c:@F@f#I#
diff --git a/test/Analysis/gmalloc.c b/test/Analysis/gmalloc.c
index 10c4fe2840..50413e2e9b 100644
--- a/test/Analysis/gmalloc.c
+++ b/test/Analysis/gmalloc.c
@@ -13,6 +13,12 @@ gpointer g_realloc(gpointer mem, gsize n_bytes);
gpointer g_try_malloc(gsize n_bytes);
gpointer g_try_malloc0(gsize n_bytes);
gpointer g_try_realloc(gpointer mem, gsize n_bytes);
+gpointer g_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_malloc0_n(gsize n_blocks, gsize n_block_bytes);
+gpointer g_try_realloc_n(gpointer mem, gsize n_blocks, gsize n_block_bytes);
void g_free(gpointer mem);
gpointer g_memdup(gconstpointer mem, guint byte_size);
@@ -25,6 +31,12 @@ void f1() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
g_free(g1);
g_free(g2);
@@ -38,6 +50,12 @@ void f2() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char));
g_free(g1);
g_free(g2);
@@ -52,8 +70,100 @@ void f3() {
gpointer g3 = g_try_malloc(n_bytes);
gpointer g4 = g_try_malloc0(n_bytes);
g3 = g_try_realloc(g3, n_bytes * 2); // expected-warning{{Potential leak of memory pointed to by 'g4'}}
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+}
+
+void f4() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g5'}}
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+}
+
+void f5() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g6'}}
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+ g_free(g5);
+}
+
+void f6() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
+
+ g_free(g1); // expected-warning{{Potential leak of memory pointed to by 'g7'}}
+ g_free(g2);
+ g_free(g3);
+ g_free(g4);
+ g_free(g5);
+ g_free(g6);
+}
+
+void f7() {
+ gpointer g1 = g_malloc(n_bytes);
+ gpointer g2 = g_malloc0(n_bytes);
+ g1 = g_realloc(g1, n_bytes * 2);
+ gpointer g3 = g_try_malloc(n_bytes);
+ gpointer g4 = g_try_malloc0(n_bytes);
+ g3 = g_try_realloc(g3, n_bytes * 2);
+ gpointer g5 = g_malloc_n(n_bytes, sizeof(char));
+ gpointer g6 = g_malloc0_n(n_bytes, sizeof(char));
+ g5 = g_realloc_n(g5, n_bytes * 2, sizeof(char));
+ gpointer g7 = g_try_malloc_n(n_bytes, sizeof(char));
+ gpointer g8 = g_try_malloc0_n(n_bytes, sizeof(char));
+ g7 = g_try_realloc_n(g7, n_bytes * 2, sizeof(char)); // expected-warning{{Potential leak of memory pointed to by 'g8'}}
g_free(g1);
g_free(g2);
g_free(g3);
+ g_free(g4);
+ g_free(g5);
+ g_free(g6);
+ g_free(g7);
}
diff --git a/test/Analysis/gtest.cpp b/test/Analysis/gtest.cpp
index 5797a773b4..98f415eea4 100644
--- a/test/Analysis/gtest.cpp
+++ b/test/Analysis/gtest.cpp
@@ -151,3 +151,17 @@ void testConstrainState(int p) {
ASSERT_TRUE(false);
clang_analyzer_warnIfReached(); // no-warning
}
+
+void testAssertSymbolicPtr(const bool *b) {
+ ASSERT_TRUE(*b); // no-crash
+
+ // FIXME: Our solver doesn't handle this well yet.
+ clang_analyzer_eval(*b); // expected-warning{{UNKNOWN}}
+}
+
+void testAssertSymbolicRef(const bool &b) {
+ ASSERT_TRUE(b); // no-crash
+
+ // FIXME: Our solver doesn't handle this well yet.
+ clang_analyzer_eval(b); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/html-diag-singlefile.c b/test/Analysis/html-diag-singlefile.c
new file mode 100644
index 0000000000..fc0dcc7a42
--- /dev/null
+++ b/test/Analysis/html-diag-singlefile.c
@@ -0,0 +1,14 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-output=html-single-file -o D30406.html %s 2>&1 | FileCheck %s
+
+// Check that single file HTML output does not process multi-file diagnostics.
+// (This used to test for PR12421, before the introduction of the html-single-file format)
+
+#include "html-diag-singlefile.h"
+
+int main(){
+ f();
+ return 0;
+}
+
+// CHECK: warning: Path diagnostic report is not generated.
diff --git a/test/Analysis/diagnostics/diag-cross-file-boundaries.h b/test/Analysis/html-diag-singlefile.h
index 1af7d1f1fb..1af7d1f1fb 100644
--- a/test/Analysis/diagnostics/diag-cross-file-boundaries.h
+++ b/test/Analysis/html-diag-singlefile.h
diff --git a/test/Analysis/html-diags-analyze-headers.c b/test/Analysis/html-diags-analyze-headers.c
new file mode 100644
index 0000000000..fa5f21de04
--- /dev/null
+++ b/test/Analysis/html-diags-analyze-headers.c
@@ -0,0 +1,10 @@
+// RUN: mkdir -p %t.dir
+// RUN: %clang_analyze_cc1 -analyzer-opt-analyze-headers -analyzer-output=html -analyzer-checker=core -o %t.dir %s
+// RUN: ls %t.dir | grep report
+// RUN: rm -rf %t.dir
+
+// This tests that we emit HTML diagnostics for reports in headers when the
+// analyzer is run with -analyzer-opt-analyze-headers. This was handled
+// incorrectly in the first iteration of D30406.
+
+#include "html-diags-analyze-headers.h"
diff --git a/test/Analysis/html-diags-analyze-headers.h b/test/Analysis/html-diags-analyze-headers.h
new file mode 100644
index 0000000000..3641ca9c04
--- /dev/null
+++ b/test/Analysis/html-diags-analyze-headers.h
@@ -0,0 +1,5 @@
+#include "html-diags-multifile.h"
+
+void test_call_macro() {
+ has_bug(0);
+}
diff --git a/test/Analysis/html-diags-multifile.c b/test/Analysis/html-diags-multifile.c
index ce1f72b6bb..ff7b625ad0 100644
--- a/test/Analysis/html-diags-multifile.c
+++ b/test/Analysis/html-diags-multifile.c
@@ -1,10 +1,9 @@
// RUN: mkdir -p %t.dir
// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %t.dir %s
-// RUN: ls %t.dir | not grep report
+// RUN: ls %t.dir | grep report
// RUN: rm -fR %t.dir
-// This tests that we do not currently emit HTML diagnostics for reports that
-// cross file boundaries.
+// This tests that we emit HTML diagnostics for reports that cross file boundaries.
#include "html-diags-multifile.h"
diff --git a/test/Analysis/html-diags.c b/test/Analysis/html-diags.c
index 182bcfbdfa..89f1e8ba79 100644
--- a/test/Analysis/html-diags.c
+++ b/test/Analysis/html-diags.c
@@ -1,12 +1,18 @@
-// RUN: rm -fR %T/dir
-// RUN: mkdir %T/dir
-// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %T/dir %s
-// RUN: ls %T/dir | grep report
+// RUN: rm -fR %t
+// RUN: mkdir %t
+// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o %t %s
+// RUN: ls %t | grep report
+
+// D30406: Test new html-single-file output
+// RUN: rm -fR %t
+// RUN: mkdir %t
+// RUN: %clang_analyze_cc1 -analyzer-output=html-single-file -analyzer-checker=core -o %t %s
+// RUN: ls %t | grep report
// PR16547: Test relative paths
-// RUN: cd %T/dir
+// RUN: cd %t
// RUN: %clang_analyze_cc1 -analyzer-output=html -analyzer-checker=core -o testrelative %s
-// RUN: ls %T/dir/testrelative | grep report
+// RUN: ls %t/testrelative | grep report
// Currently this test mainly checks that the HTML diagnostics doesn't crash
// when handling macros will calls with macros. We should actually validate
diff --git a/test/Analysis/initializer.cpp b/test/Analysis/initializer.cpp
index c73635686d..e9658a067c 100644
--- a/test/Analysis/initializer.cpp
+++ b/test/Analysis/initializer.cpp
@@ -1,7 +1,9 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.Malloc,cplusplus.NewDeleteLeaks,debug.ExprInspection -analyzer-config c++-inlining=constructors -std=c++11 -verify %s
void clang_analyzer_eval(bool);
+#include "Inputs/system-header-simulator-cxx.h"
+
class A {
int x;
public:
@@ -204,3 +206,17 @@ struct C {
const char(&f)[2];
};
}
+
+namespace CXX_initializer_lists {
+struct C {
+ C(std::initializer_list<int *> list);
+};
+void foo() {
+ C empty{}; // no-crash
+
+ // Do not warn that 'x' leaks. It might have been deleted by
+ // the destructor of 'c'.
+ int *x = new int;
+ C c{x}; // no-warning
+}
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.c b/test/Analysis/inlining/inline-defensive-checks.c
index 4029da651b..9f211b502b 100644
--- a/test/Analysis/inlining/inline-defensive-checks.c
+++ b/test/Analysis/inlining/inline-defensive-checks.c
@@ -1,7 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core -analyzer-config suppress-inlined-defensive-checks=true -verify %s
// Perform inline defensive checks.
-void idc(int *p) {
+void idc(void *p) {
if (p)
;
}
@@ -139,3 +139,54 @@ void idcTrackZeroThroughDoubleAssignemnt(int x) {
int z = y;
idcTriggerZeroValueThroughCall(z);
}
+
+struct S {
+ int f1;
+ int f2;
+};
+
+void idcTrackZeroValueThroughUnaryPointerOperators(struct S *s) {
+ idc(s);
+ *(&(s->f1)) = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithOffset1(struct S *s) {
+ idc(s);
+ int *x = &(s->f2);
+ *x = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithOffset2(struct S *s) {
+ idc(s);
+ int *x = &(s->f2) - 1;
+ // FIXME: Should not warn.
+ *x = 7; // expected-warning{{Dereference of null pointer}}
+}
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithAssignment(struct S *s) {
+ idc(s);
+ int *x = &(s->f1);
+ *x = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignment(struct S *s) {
+ idc(s);
+ int *x = &*&(s->f1);
+ *x = 7; // no-warning
+}
+
+void idcTrackZeroValueThroughManyUnaryPointerOperatorsWithAssignmentAndUnaryIncrement(struct S *s) {
+ idc(s);
+ int *x = &*&((++s)->f1);
+ *x = 7; // no-warning
+}
+
+
+struct S2 {
+ int a[1];
+};
+
+void idcTrackZeroValueThroughUnaryPointerOperatorsWithArrayField(struct S2 *s) {
+ idc(s);
+ *(&(s->a[0])) = 7; // no-warning
+}
diff --git a/test/Analysis/inlining/inline-defensive-checks.cpp b/test/Analysis/inlining/inline-defensive-checks.cpp
index 6a803fa695..eaae8d2ae2 100644
--- a/test/Analysis/inlining/inline-defensive-checks.cpp
+++ b/test/Analysis/inlining/inline-defensive-checks.cpp
@@ -70,4 +70,17 @@ int *retNull() {
void test(int *p1, int *p2) {
idc(p1);
Foo f(p1);
-} \ No newline at end of file
+}
+
+struct Bar {
+ int x;
+};
+void idcBar(Bar *b) {
+ if (b)
+ ;
+}
+void testRefToField(Bar *b) {
+ idcBar(b);
+ int &x = b->x; // no-warning
+ x = 5;
+}
diff --git a/test/Analysis/iterator-past-end.cpp b/test/Analysis/iterator-past-end.cpp
deleted file mode 100644
index 252d1044bd..0000000000
--- a/test/Analysis/iterator-past-end.cpp
+++ /dev/null
@@ -1,205 +0,0 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=false %s -verify
-// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorPastEnd -analyzer-eagerly-assume -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
-
-#include "Inputs/system-header-simulator-cxx.h"
-
-void simple_good(const std::vector<int> &v) {
- auto i = v.end();
- if (i != v.end())
- *i; // no-warning
-}
-
-void simple_good_negated(const std::vector<int> &v) {
- auto i = v.end();
- if (!(i == v.end()))
- *i; // no-warning
-}
-
-void simple_bad(const std::vector<int> &v) {
- auto i = v.end();
- *i; // expected-warning{{Iterator accessed past its end}}
-}
-
-void copy(const std::vector<int> &v) {
- auto i1 = v.end();
- auto i2 = i1;
- *i2; // expected-warning{{Iterator accessed past its end}}
-}
-
-void decrease(const std::vector<int> &v) {
- auto i = v.end();
- --i;
- *i; // no-warning
-}
-
-void copy_and_decrease1(const std::vector<int> &v) {
- auto i1 = v.end();
- auto i2 = i1;
- --i1;
- *i1; // no-warning
-}
-
-void copy_and_decrease2(const std::vector<int> &v) {
- auto i1 = v.end();
- auto i2 = i1;
- --i1;
- *i2; // expected-warning{{Iterator accessed past its end}}
-}
-
-void copy_and_increase1(const std::vector<int> &v) {
- auto i1 = v.begin();
- auto i2 = i1;
- ++i1;
- if (i1 == v.end())
- *i2; // no-warning
-}
-
-void copy_and_increase2(const std::vector<int> &v) {
- auto i1 = v.begin();
- auto i2 = i1;
- ++i1;
- if (i2 == v.end())
- *i2; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find(std::vector<int> &vec, int e) {
- auto first = std::find(vec.begin(), vec.end(), e);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find(std::vector<int> &vec, int e) {
- auto first = std::find(vec.begin(), vec.end(), e);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find_end(std::vector<int> &vec, std::vector<int> &seq) {
- auto last = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != last)
- *last; // no-warning
-}
-
-void bad_find_end(std::vector<int> &vec, std::vector<int> &seq) {
- auto last = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
- *last; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find_first_of(std::vector<int> &vec, std::vector<int> &seq) {
- auto first =
- std::find_first_of(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find_first_of(std::vector<int> &vec, std::vector<int> &seq) {
- auto first = std::find_end(vec.begin(), vec.end(), seq.begin(), seq.end());
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-bool odd(int i) { return i % 2; }
-
-void good_find_if(std::vector<int> &vec) {
- auto first = std::find_if(vec.begin(), vec.end(), odd);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find_if(std::vector<int> &vec, int e) {
- auto first = std::find_if(vec.begin(), vec.end(), odd);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_find_if_not(std::vector<int> &vec) {
- auto first = std::find_if_not(vec.begin(), vec.end(), odd);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_find_if_not(std::vector<int> &vec, int e) {
- auto first = std::find_if_not(vec.begin(), vec.end(), odd);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_lower_bound(std::vector<int> &vec, int e) {
- auto first = std::lower_bound(vec.begin(), vec.end(), e);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_lower_bound(std::vector<int> &vec, int e) {
- auto first = std::lower_bound(vec.begin(), vec.end(), e);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_upper_bound(std::vector<int> &vec, int e) {
- auto last = std::lower_bound(vec.begin(), vec.end(), e);
- if (vec.end() != last)
- *last; // no-warning
-}
-
-void bad_upper_bound(std::vector<int> &vec, int e) {
- auto last = std::lower_bound(vec.begin(), vec.end(), e);
- *last; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_search(std::vector<int> &vec, std::vector<int> &seq) {
- auto first = std::search(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_search(std::vector<int> &vec, std::vector<int> &seq) {
- auto first = std::search(vec.begin(), vec.end(), seq.begin(), seq.end());
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void good_search_n(std::vector<int> &vec, std::vector<int> &seq) {
- auto nth = std::search_n(vec.begin(), vec.end(), seq.begin(), seq.end());
- if (vec.end() != nth)
- *nth; // no-warning
-}
-
-void bad_search_n(std::vector<int> &vec, std::vector<int> &seq) {
- auto nth = std::search_n(vec.begin(), vec.end(), seq.begin(), seq.end());
- *nth; // expected-warning{{Iterator accessed past its end}}
-}
-
-template <class InputIterator, class T>
-InputIterator nonStdFind(InputIterator first, InputIterator last,
- const T &val) {
- for (auto i = first; i != last; ++i) {
- if (*i == val) {
- return i;
- }
- }
- return last;
-}
-
-void good_non_std_find(std::vector<int> &vec, int e) {
- auto first = nonStdFind(vec.begin(), vec.end(), e);
- if (vec.end() != first)
- *first; // no-warning
-}
-
-void bad_non_std_find(std::vector<int> &vec, int e) {
- auto first = nonStdFind(vec.begin(), vec.end(), e);
- *first; // expected-warning{{Iterator accessed past its end}}
-}
-
-void tricky(std::vector<int> &vec, int e) {
- const auto first = vec.begin();
- const auto comp1 = (first != vec.end()), comp2 = (first == vec.end());
- if (comp1)
- *first;
-}
-
-void loop(std::vector<int> &vec, int e) {
- auto start = vec.begin();
- while (true) {
- auto item = std::find(start, vec.end(), e);
- if (item == vec.end())
- break;
- *item; // no-warning
- start = ++item; // no-warning
- }
-}
diff --git a/test/Analysis/iterator-range.cpp b/test/Analysis/iterator-range.cpp
new file mode 100644
index 0000000000..79b45188ab
--- /dev/null
+++ b/test/Analysis/iterator-range.cpp
@@ -0,0 +1,19 @@
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-eagerly-assume -analyzer-config c++-container-inlining=false %s -verify
+// RUN: %clang_analyze_cc1 -std=c++11 -analyzer-checker=core,cplusplus,alpha.cplusplus.IteratorRange -analyzer-eagerly-assume -analyzer-config c++-container-inlining=true -DINLINE=1 %s -verify
+
+#include "Inputs/system-header-simulator-cxx.h"
+
+void clang_analyzer_warnIfReached();
+
+void simple_good_end(const std::vector<int> &v) {
+ auto i = v.end();
+ if (i != v.end()) {
+ clang_analyzer_warnIfReached();
+ *i; // no-warning
+ }
+}
+
+void simple_bad_end(const std::vector<int> &v) {
+ auto i = v.end();
+ *i; // expected-warning{{Iterator accessed outside of its range}}
+}
diff --git a/test/Analysis/lifetime-cfg-output.cpp b/test/Analysis/lifetime-cfg-output.cpp
new file mode 100644
index 0000000000..1e6f56df6a
--- /dev/null
+++ b/test/Analysis/lifetime-cfg-output.cpp
@@ -0,0 +1,783 @@
+// RUN: %clang_cc1 -fcxx-exceptions -fexceptions -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-lifetime=true -analyzer-config cfg-implicit-dtors=false %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+extern bool UV;
+class A {
+public:
+ // CHECK: [B2 (ENTRY)]
+ // CHECK-NEXT: Succs (1): B1
+ // CHECK: [B1]
+ // CHECK-NEXT: 1: true
+ // CHECK-NEXT: 2: UV
+ // CHECK-NEXT: 3: [B1.2] = [B1.1]
+ // CHECK-NEXT: Preds (1): B2
+ // CHECK-NEXT: Succs (1): B0
+ // CHECK: [B0 (EXIT)]
+ // CHECK-NEXT: Preds (1): B1
+ A() {
+ UV = true;
+ }
+ // CHECK: [B3 (ENTRY)]
+ // CHECK-NEXT: Succs (1): B2
+ // CHECK: [B1]
+ // CHECK-NEXT: 1: 0
+ // CHECK-NEXT: 2: this
+ // CHECK-NEXT: 3: [B1.2]->p
+ // CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, LValueToRValue, int *)
+ // CHECK-NEXT: 5: *[B1.4]
+ // CHECK-NEXT: 6: [B1.5] = [B1.1]
+ // CHECK-NEXT: Preds (1): B2
+ // CHECK-NEXT: Succs (1): B0
+ // CHECK: [B2]
+ // CHECK-NEXT: 1: this
+ // CHECK-NEXT: 2: [B2.1]->p
+ // CHECK-NEXT: 3: [B2.2] (ImplicitCastExpr, LValueToRValue, int *)
+ // CHECK-NEXT: 4: [B2.3] (ImplicitCastExpr, PointerToBoolean, _Bool)
+ // CHECK-NEXT: T: if [B2.4]
+ // CHECK-NEXT: Preds (1): B3
+ // CHECK-NEXT: Succs (2): B1 B0
+ // CHECK: [B0 (EXIT)]
+ // CHECK-NEXT: Preds (2): B1 B2
+ ~A() {
+ if (p)
+ *p = 0;
+ }
+ // CHECK: [B2 (ENTRY)]
+ // CHECK-NEXT: Succs (1): B1
+ // CHECK: [B1]
+ // CHECK-NEXT: 1: 1
+ // CHECK-NEXT: 2: return [B1.1];
+ // CHECK-NEXT: Preds (1): B2
+ // CHECK-NEXT: Succs (1): B0
+ // CHECK: [B0 (EXIT)]
+ // CHECK-NEXT: Preds (1): B1
+ operator int() const { return 1; }
+ int *p;
+};
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B1.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: const A &b = a;
+// CHECK-NEXT: 6: A() (CXXConstructExpr, class A)
+// CHECK-NEXT: 7: [B1.6] (BindTemporary)
+// CHECK-NEXT: 8: [B1.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B1.8]
+// CHECK-NEXT: 10: const A &c = A();
+// CHECK-NEXT: 11: [B1.10] (Lifetime ends)
+// CHECK-NEXT: 12: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 13: [B1.5] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_const_ref() {
+ A a;
+ const A &b = a;
+ const A &c = A();
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A [2])
+// CHECK-NEXT: 2: A a[2];
+// CHECK-NEXT: 3: (CXXConstructExpr, class A [0])
+// CHECK-NEXT: 4: A b[0];
+// lifetime of a ends when its destructors are run
+// CHECK-NEXT: 5: [B1.2] (Lifetime ends)
+// lifetime of b ends when its storage duration ends
+// CHECK-NEXT: 6: [B1.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_array() {
+ A a[2];
+ A b[0];
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A c;
+// CHECK-NEXT: 5: (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A d;
+// CHECK-NEXT: 7: [B1.6] (Lifetime ends)
+// CHECK-NEXT: 8: [B1.4] (Lifetime ends)
+// CHECK-NEXT: 9: (CXXConstructExpr, class A)
+// CHECK-NEXT: 10: A b;
+// CHECK-NEXT: 11: [B1.10] (Lifetime ends)
+// CHECK-NEXT: 12: [B1.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_scope() {
+ A a;
+ {
+ A c;
+ A d;
+ }
+ A b;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B3.4] (Lifetime ends)
+// CHECK-NEXT: 5: [B3.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B3.4] (Lifetime ends)
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b;
+// CHECK-NEXT: 5: UV
+// CHECK-NEXT: 6: [B3.5] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B3.6]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (2): B2 B1
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B2
+void test_return() {
+ A a;
+ A b;
+ if (UV)
+ return;
+ A c;
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.6] (Lifetime ends)
+// CHECK-NEXT: 2: [B4.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B4]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: [B4.4] (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A b = a;
+// CHECK-NEXT: 7: b
+// CHECK-NEXT: 8: [B4.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B4.8].operator int
+// CHECK-NEXT: 10: [B4.8]
+// CHECK-NEXT: 11: [B4.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 12: [B4.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B4.12]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B3 B2
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_if_implicit_scope() {
+ A a;
+ if (A b = a)
+ A c;
+ else
+ A c;
+}
+
+// CHECK: [B9 (ENTRY)]
+// CHECK-NEXT: Succs (1): B8
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B8.6] (Lifetime ends)
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: A e;
+// CHECK-NEXT: 4: [B1.3] (Lifetime ends)
+// CHECK-NEXT: 5: [B8.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B4.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B4.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B8.6] (Lifetime ends)
+// CHECK-NEXT: 4: [B8.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B4]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B4.4]
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (2): B3 B2
+// CHECK: [B5]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B5.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B7.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B6]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B7.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B8.6] (Lifetime ends)
+// CHECK-NEXT: 4: [B8.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B7]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B7.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.4]
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: a
+// CHECK-NEXT: 4: [B8.3] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 5: [B8.4] (CXXConstructExpr, class A)
+// CHECK-NEXT: 6: A b = a;
+// CHECK-NEXT: 7: b
+// CHECK-NEXT: 8: [B8.7] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 9: [B8.8].operator int
+// CHECK-NEXT: 10: [B8.8]
+// CHECK-NEXT: 11: [B8.10] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 12: [B8.11] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B8.12]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B7 B4
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (3): B1 B3 B6
+void test_if_jumps() {
+ A a;
+ if (A b = a) {
+ A c;
+ if (UV)
+ return;
+ A d;
+ } else {
+ A c;
+ if (UV)
+ return;
+ A d;
+ }
+ A e;
+}
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.4] (Lifetime ends)
+// CHECK-NEXT: 2: [B5.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B4.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: a
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B4.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b = a;
+// CHECK-NEXT: 5: b
+// CHECK-NEXT: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B4.6].operator int
+// CHECK-NEXT: 8: [B4.6]
+// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: while [B4.10]
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 B1
+// CHECK: [B5]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_while_implicit_scope() {
+ A a;
+ while (A b = a)
+ A c;
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 2: (CXXConstructExpr, class A)
+// CHECK-NEXT: 3: A e;
+// CHECK-NEXT: 4: [B1.3] (Lifetime ends)
+// CHECK-NEXT: 5: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B8 B10
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (2): B3 B6
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 5: [B10.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 4: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B5]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B5.2]
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (2): B4 B3
+// CHECK: [B6]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 2: [B10.4] (Lifetime ends)
+// CHECK-NEXT: T: continue;
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B7]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.2]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B9]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (2): B8 B7
+// CHECK: [B10]
+// CHECK-NEXT: 1: a
+// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B10.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b = a;
+// CHECK-NEXT: 5: b
+// CHECK-NEXT: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B10.6].operator int
+// CHECK-NEXT: 8: [B10.6]
+// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: while [B10.10]
+// CHECK-NEXT: Preds (2): B2 B11
+// CHECK-NEXT: Succs (2): B9 B1
+// CHECK: [B11]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B4
+void test_while_jumps() {
+ A a;
+ while (A b = a) {
+ A c;
+ if (UV)
+ break;
+ if (UV)
+ continue;
+ if (UV)
+ return;
+ A d;
+ }
+ A e;
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B8 B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: do ... while [B2.2]
+// CHECK-NEXT: Preds (2): B3 B6
+// CHECK-NEXT: Succs (2): B10 B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B9.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B5]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B5.2]
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (2): B4 B3
+// CHECK: [B6]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: continue;
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B7]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.2]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B9]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A b;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (2): B10 B11
+// CHECK-NEXT: Succs (2): B8 B7
+// CHECK: [B10]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B9
+// CHECK: [B11]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B9
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B4
+void test_do_jumps() {
+ A a;
+ do {
+ A b;
+ if (UV)
+ break;
+ if (UV)
+ continue;
+ if (UV)
+ return;
+ A c;
+ } while (UV);
+ A d;
+}
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B4.4] (Lifetime ends)
+// CHECK-NEXT: 2: [B5.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A c;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B4.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: a
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B4.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b = a;
+// CHECK-NEXT: 5: b
+// CHECK-NEXT: 6: [B4.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B4.6].operator int
+// CHECK-NEXT: 8: [B4.6]
+// CHECK-NEXT: 9: [B4.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B4.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: for (...; [B4.10]; )
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 B1
+// CHECK: [B5]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_for_implicit_scope() {
+ for (A a; A b = a;)
+ A c;
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+// CHECK: [B1]
+// CHECK-NEXT: 1: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 2: [B11.4] (Lifetime ends)
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A f;
+// CHECK-NEXT: 5: [B1.4] (Lifetime ends)
+// CHECK-NEXT: 6: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B8 B10
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: Preds (2): B3 B6
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B3]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A e;
+// CHECK-NEXT: 3: [B3.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 5: [B10.4] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B4]
+// CHECK-NEXT: 1: return;
+// CHECK-NEXT: 2: [B9.2] (Lifetime ends)
+// CHECK-NEXT: 3: [B10.4] (Lifetime ends)
+// CHECK-NEXT: 4: [B11.4] (Lifetime ends)
+// CHECK-NEXT: 5: [B11.2] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B5]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B5.2]
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (2): B4 B3
+// CHECK: [B6]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: continue;
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B7]
+// CHECK-NEXT: 1: UV
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B7.2]
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (2): B6 B5
+// CHECK: [B8]
+// CHECK-NEXT: 1: [B9.2] (Lifetime ends)
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B9]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A d;
+// CHECK-NEXT: 3: UV
+// CHECK-NEXT: 4: [B9.3] (ImplicitCastExpr, LValueToRValue, _Bool)
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (2): B8 B7
+// CHECK: [B10]
+// CHECK-NEXT: 1: b
+// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 3: [B10.2] (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A c = b;
+// CHECK-NEXT: 5: c
+// CHECK-NEXT: 6: [B10.5] (ImplicitCastExpr, NoOp, const class A)
+// CHECK-NEXT: 7: [B10.6].operator int
+// CHECK-NEXT: 8: [B10.6]
+// CHECK-NEXT: 9: [B10.8] (ImplicitCastExpr, UserDefinedConversion, int)
+// CHECK-NEXT: 10: [B10.9] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: for (...; [B10.10]; )
+// CHECK-NEXT: Preds (2): B2 B11
+// CHECK-NEXT: Succs (2): B9 B1
+// CHECK: [B11]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: (CXXConstructExpr, class A)
+// CHECK-NEXT: 4: A b;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B10
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (2): B1 B4
+void test_for_jumps() {
+ A a;
+ for (A b; A c = b;) {
+ A d;
+ if (UV)
+ break;
+ if (UV)
+ continue;
+ if (UV)
+ return;
+ A e;
+ }
+ A f;
+}
+
+// CHECK: [B2 (ENTRY)]
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B1]
+// CHECK-NEXT: 1: (CXXConstructExpr, class A)
+// CHECK-NEXT: 2: A a;
+// CHECK-NEXT: 3: int n;
+// CHECK-NEXT: 4: n
+// CHECK-NEXT: 5: &[B1.4]
+// CHECK-NEXT: 6: a
+// CHECK-NEXT: 7: [B1.6].p
+// CHECK-NEXT: 8: [B1.7] = [B1.5]
+// CHECK-NEXT: 9: [B1.2] (Lifetime ends)
+// CHECK-NEXT: 10: [B1.3] (Lifetime ends)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void test_trivial_vs_non_trivial_order() {
+ A a;
+ int n;
+ a.p = &n;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: a:
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: i
+// CHECK-NEXT: 3: [B1.2] = [B1.1]
+// CHECK-NEXT: 4: [B2.1] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: T: goto a;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void goto_past_declaration() {
+ goto a;
+ int i;
+a:
+ i = 1;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: a:
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: k
+// CHECK-NEXT: 3: [B1.2] = [B1.1]
+// CHECK-NEXT: 4: [B2.4] (Lifetime ends)
+// CHECK-NEXT: Preds (2): B2 B3
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: 1: int j;
+// CHECK-NEXT: 2: [B2.1] (Lifetime ends)
+// CHECK-NEXT: 3: [B3.1] (Lifetime ends)
+// CHECK-NEXT: 4: int k;
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B3]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: 2: [B3.1] (Lifetime ends)
+// CHECK-NEXT: T: goto a;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void goto_past_declaration2() {
+ {
+ int i;
+ goto a;
+ int j;
+ }
+ {
+ int k;
+ a:
+ k = 1;
+ }
+}
+
+struct B {
+ ~B();
+};
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+// CHECK: [B1]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B1.1]++
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: 4: [B3.1] (Lifetime ends)
+// CHECK-NEXT: Succs (1): B0
+// CHECK: [B2]
+// CHECK-NEXT: label:
+// CHECK-NEXT: 1: (CXXConstructExpr, struct B)
+// CHECK-NEXT: 2: B b;
+// CHECK-NEXT: 3: [B2.2] (Lifetime ends)
+// CHECK-NEXT: T: goto label;
+// CHECK-NEXT: Preds (2): B3 B2
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B3]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+int backpatched_goto() {
+ int i;
+label:
+ B b;
+ goto label;
+ i++;
+}
diff --git a/test/Analysis/lit.local.cfg b/test/Analysis/lit.local.cfg
index acae2bdcd4..a594c5dada 100644
--- a/test/Analysis/lit.local.cfg
+++ b/test/Analysis/lit.local.cfg
@@ -1,30 +1,13 @@
-import lit.TestRunner
-import sys
+# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
-# Custom format class for static analyzer tests
-class AnalyzerTest(lit.formats.ShTest, object):
+import site
- def execute(self, test, litConfig):
- result = self.executeWithAnalyzeSubstitution(test, litConfig, '-analyzer-constraints=range')
-
- if result.code == lit.Test.FAIL:
- return result
-
- return result
-
- def executeWithAnalyzeSubstitution(self, test, litConfig, substitution):
- saved_substitutions = list(test.config.substitutions)
- test.config.substitutions.append(('%analyze', substitution))
- result = lit.TestRunner.executeShTest(test, litConfig, self.execute_external)
- test.config.substitutions = saved_substitutions
-
- return result
-
-# This results in a pickling-related failure on Windows
-if (not sys.platform in ['win32']):
- config.test_format = AnalyzerTest(config.test_format.execute_external)
-else:
- config.substitutions.append(('%analyze', '-analyzer-constraints=range'))
+# Load the custom analyzer test format, which runs the test again with Z3 if it
+# is available.
+site.addsitedir(os.path.dirname(__file__))
+import analyzer_test
+config.test_format = analyzer_test.AnalyzerTest(
+ config.test_format.execute_external)
if not config.root.clang_staticanalyzer:
config.unsupported = True
diff --git a/test/Analysis/localization-aggressive.m b/test/Analysis/localization-aggressive.m
index 346cf3ef22..ea5e0b1529 100644
--- a/test/Analysis/localization-aggressive.m
+++ b/test/Analysis/localization-aggressive.m
@@ -61,8 +61,16 @@ int random();
NSString *CFNumberFormatterCreateStringWithNumber(float x);
+ (NSString *)forceLocalized:(NSString *)str
__attribute__((annotate("returns_localized_nsstring")));
++ (NSString *)takesLocalizedString:
+ (NSString *)__attribute__((annotate("takes_localized_nsstring")))str;
@end
+NSString *
+takesLocalizedString(NSString *str
+ __attribute__((annotate("takes_localized_nsstring")))) {
+ return str;
+}
+
// Test cases begin here
@implementation LocalizationTestSuite
@@ -75,6 +83,8 @@ NSString *ForceLocalized(NSString *str) { return str; }
return str;
}
++ (NSString *) takesLocalizedString:(NSString *)str { return str; }
+
// An ObjC method that returns a localized string
+ (NSString *)unLocalizedStringMethod {
return @"UnlocalizedString";
@@ -269,4 +279,13 @@ NSString *ForceLocalized(NSString *str) { return str; }
NSString *string2 = POSSIBLE_FALSE_POSITIVE(@"Hello", @"Hello"); // no-warning
}
+- (void)testTakesLocalizedString {
+ NSString *localized = NSLocalizedString(@"Hello", @"World");
+ NSString *alsoLocalized = [LocalizationTestSuite takesLocalizedString:localized]; // no-warning
+ NSString *stillLocalized = [LocalizationTestSuite takesLocalizedString:alsoLocalized]; // no-warning
+ takesLocalizedString(stillLocalized); // no-warning
+
+ [LocalizationTestSuite takesLocalizedString:@"not localized"]; // expected-warning {{User-facing text should use localized string macro}}
+ takesLocalizedString(@"not localized"); // expected-warning {{User-facing text should use localized string macro}}
+}
@end
diff --git a/test/Analysis/loop-unrolling.cpp b/test/Analysis/loop-unrolling.cpp
new file mode 100644
index 0000000000..844d1f18ea
--- /dev/null
+++ b/test/Analysis/loop-unrolling.cpp
@@ -0,0 +1,381 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -analyzer-config unroll-loops=true,cfg-loopexit=true -verify -std=c++11 %s
+
+void clang_analyzer_numTimesReached();
+void clang_analyzer_warnIfReached();
+
+int getNum();
+void foo(int &);
+
+int simple_unroll1() {
+ int a[9];
+ int k = 42;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_unroll2() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ a[i] = 42;
+ }
+
+ for (int j = 0; j <= 9; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ a[j] = 42;
+ }
+
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_no_unroll1() {
+ int a[9];
+ int k = 42;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ foo(i);
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_no_unroll2() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ i += getNum();
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_no_unroll3() {
+ int a[9];
+ int k = 42;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ (void)&i;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int simple_no_unroll4() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ int &j = i;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int simple_no_unroll5() {
+ int a[9];
+ int k = 42;
+ int i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ int &j{i};
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int make_new_branches_loop_cached() {
+ for (int i = 0; i < 8; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ if(getNum()){
+ (void) i; // Since this Stmt does not change the State the analyzer
+ // won't make a new execution path but reuse the earlier nodes.
+ }
+ }
+ clang_analyzer_warnIfReached(); // no-warning
+ return 0;
+}
+
+int make_new_branches_loop_uncached() {
+ int l = 2;
+ for (int i = 0; i < 8; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ if(getNum()){
+ ++l;
+ }
+ }
+ clang_analyzer_warnIfReached(); // no-warning
+ return 0;
+}
+
+int make_new_branches_loop_uncached2() {
+ int l = 2;
+ for (int i = 0; i < 8; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ if(getNum()){
+ ++l;
+ }
+ (void)&i; // This ensures that the loop won't be unrolled.
+ }
+ clang_analyzer_warnIfReached(); // no-warning
+ return 0;
+}
+
+
+int escape_before_loop_no_unroll1() {
+ int a[9];
+ int k = 42;
+ int i;
+ int &j = i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int escape_before_loop_no_unroll2() {
+ int a[9];
+ int k = 42;
+ int i;
+ int *p = &i;
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int escape_before_loop_no_unroll3() {
+ int a[9];
+ int k = 42;
+ int i;
+ foo(i);
+ for (i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int nested_outer_unrolled() {
+ int a[9];
+ int k = 42;
+ int j = 0;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (j = 0; j < 9; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ a[j] = 22;
+ (void) &j; // ensures that the inner loop won't be unrolled
+ }
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // no-warning
+ return 0;
+}
+
+int nested_inner_unrolled() {
+ int a[9];
+ int k = 42;
+ int j = 0;
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ for (j = 0; j < 8; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{32}}
+ a[j] = 22;
+ }
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int nested_both_unrolled() {
+ int a[9];
+ int k = 42;
+ int j = 0;
+ for (int i = 0; i < 7; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{7}}
+ for (j = 0; j < 6; ++j) {
+ clang_analyzer_numTimesReached(); // expected-warning {{42}}
+ a[j] = 22;
+ }
+ a[i] = 42;
+ }
+ int b = 22 / (k - 42); // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int simple_known_bound_loop() {
+ for (int i = 2; i < 12; i++) {
+ // This function is inlined in nested_inlined_unroll1()
+ clang_analyzer_numTimesReached(); // expected-warning {{90}}
+ }
+ return 0;
+}
+
+int simple_unknown_bound_loop() {
+ for (int i = 2; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ }
+ return 0;
+}
+
+int nested_inlined_unroll1() {
+ int k;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ k = simple_known_bound_loop(); // no reevaluation without inlining
+ }
+ int a = 22 / k; // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int nested_inlined_no_unroll1() {
+ int k;
+ for (int i = 0; i < 9; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{15}}
+ k = simple_unknown_bound_loop(); // reevaluation without inlining, splits the state as well
+ }
+ int a = 22 / k; // no-warning
+ return 0;
+}
+
+int recursion_unroll1(bool b) {
+ int k = 2;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{13}}
+ if(i == 0 && b) // Splits the state in the first iteration but the recursion
+ // call will be unrolled anyway since the condition is known there.
+ recursion_unroll1(false);
+ clang_analyzer_numTimesReached(); // expected-warning {{14}}
+ }
+ int a = 22 / k; // no-warning
+ return 0;
+}
+
+int recursion_unroll2(bool b) {
+ int k = 0;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ if(i == 0 && b)
+ recursion_unroll2(false);
+ clang_analyzer_numTimesReached(); // expected-warning {{9}}
+ }
+ int a = 22 / k; // expected-warning {{Division by zero}}
+ return 0;
+}
+
+int recursion_unroll3(bool b) {
+ int k = 2;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ if (i == 4 && b) {
+ recursion_unroll3(false);
+ break;
+ }
+ clang_analyzer_numTimesReached(); // expected-warning {{10}}
+ }
+ int a = 22 / k;
+ return 0;
+}
+
+int recursion_unroll4(bool b) {
+ int k = 2;
+ for (int i = 0; i < 5; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{13}}
+ if(i == 0 && b) {
+ recursion_unroll4(false);
+ continue;
+ }
+ clang_analyzer_numTimesReached(); // expected-warning {{13}}
+ }
+ int a = 22 / k;
+ return 0;
+}
+
+int loop_exit_while_empty_loop_stack() {
+ if (getNum())
+ for (int i = 1; i < 8; i++)
+ ;
+ return 0;
+}
+
+int num_steps_on_limit() {
+ for (int i = 0; i < 128; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ return 0;
+}
+
+int num_steps_over_limit1() {
+ for (int i = 0; i < 129; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ return 0;
+}
+
+int num_steps_on_limit2() {
+ for (int i = 0; i < 2; i++) {
+ for (int j = 0; j < 64; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_over_limit2() {
+ for (int i = 0; i < 2; i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (int j = 0; j <= 64; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_on_limit3() {
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ for (int j = 0; j < 32; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{128}}
+ }
+ }
+ return 0;
+}
+
+int num_steps_over_limit3() {
+ for (int i = 0; i < getNum(); i++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{1}}
+ for (int j = 0; j < 33; j++) {
+ clang_analyzer_numTimesReached(); // expected-warning {{4}}
+ }
+ }
+ return 0;
+}
+
+
+void pr34943() {
+ for (int i = 0; i < 6L; ++i) {
+ clang_analyzer_numTimesReached(); // expected-warning {{6}}
+ }
+}
diff --git a/test/Analysis/loopexit-cfg-output.cpp b/test/Analysis/loopexit-cfg-output.cpp
new file mode 100644
index 0000000000..8e53ce3066
--- /dev/null
+++ b/test/Analysis/loopexit-cfg-output.cpp
@@ -0,0 +1,476 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.DumpCFG -analyzer-config cfg-loopexit=true %s > %t 2>&1
+// RUN: FileCheck --input-file=%t %s
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: 2: return;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B2.1]++
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B3.1]++
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 12
+// CHECK-NEXT: 4: [B4.2] < [B4.3]
+// CHECK-NEXT: T: for (...; [B4.4]; ...)
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 B1
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: 0
+// CHECK-NEXT: 2: int i = 0;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_forloop1() {
+ for (int i = 0; i < 12; i++) {
+ i++;
+ }
+ return;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: T: for (; ; )
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): B2 NULL
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_forloop2() {
+ for (;;)
+ ;
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: int i;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: true
+// CHECK-NEXT: T: while [B4.1]
+// CHECK-NEXT: Preds (2): B2 B5
+// CHECK-NEXT: Succs (2): B3 NULL
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while1() {
+ while (true) {
+ int i;
+ }
+}
+
+// CHECK: [B5 (ENTRY)]
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: 2: 2
+// CHECK-NEXT: 3: int k = 2;
+// CHECK-NEXT: 4: return;
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: l
+// CHECK-NEXT: 2: [B3.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 42
+// CHECK-NEXT: 4: [B3.2] < [B3.3]
+// CHECK-NEXT: T: while [B3.4]
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): B2 B1
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: int l;
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while2() {
+ int l;
+ while (l < 42)
+ ;
+ int k = 2;
+ return;
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: false
+// CHECK-NEXT: T: while [B3.1]
+// CHECK-NEXT: Preds (2): B2 B4
+// CHECK-NEXT: Succs (2): NULL B1
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_while3() {
+ while (false) {
+ ;
+ }
+}
+
+// CHECK: [B4 (ENTRY)]
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: false
+// CHECK-NEXT: T: do ... while [B2.1]
+// CHECK-NEXT: Preds (2): B3 B4
+// CHECK-NEXT: Succs (2): NULL B1
+
+// CHECK: [B3]
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_dowhile1() {
+ do {
+ } while (false);
+}
+
+// CHECK: [B6 (ENTRY)]
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: 2: j
+// CHECK-NEXT: 3: [B1.2]--
+// CHECK-NEXT: 4: return;
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B2.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 20
+// CHECK-NEXT: 4: [B2.2] < [B2.3]
+// CHECK-NEXT: T: do ... while [B2.4]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (2): B4 B1
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: 2
+// CHECK-NEXT: 3: [B3.1] += [B3.2]
+// CHECK-NEXT: Preds (2): B4 B5
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: Preds (1): B2
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: 2
+// CHECK-NEXT: 2: int j = 2;
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B3
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_dowhile2() {
+ int j = 2;
+ do {
+ j += 2;
+ } while (j < 20);
+ j--;
+ return;
+}
+
+// CHECK: [B10 (ENTRY)]
+// CHECK-NEXT: Succs (1): B9
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B4.1]++
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1]++
+// CHECK-NEXT: Preds (1): B6
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B6]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B6.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B6.2] < [B6.3]
+// CHECK-NEXT: T: for (...; [B6.4]; ...)
+// CHECK-NEXT: Preds (2): B4 B7
+// CHECK-NEXT: Succs (2): B5 B3
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: 1
+// CHECK-NEXT: 2: int j = 1;
+// CHECK-NEXT: Preds (1): B8
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B8]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B8.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 2
+// CHECK-NEXT: 4: [B8.2] < [B8.3]
+// CHECK-NEXT: T: while [B8.4]
+// CHECK-NEXT: Preds (2): B2 B9
+// CHECK-NEXT: Succs (2): B7 B1
+
+// CHECK: [B9]
+// CHECK-NEXT: 1: 40
+// CHECK-NEXT: 2: -[B9.1]
+// CHECK-NEXT: 3: int i = -40;
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void nested_loops1() {
+ int i = -40;
+ while (i < 2) {
+ for (int j = 1; j < 6; j++)
+ i++;
+ }
+}
+
+// CHECK: [B9 (ENTRY)]
+// CHECK-NEXT: Succs (1): B8
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: Preds (1): B7
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B2.1]++
+// CHECK-NEXT: Preds (1): B3
+// CHECK-NEXT: Succs (1): B7
+
+// CHECK: [B3]
+// CHECK-NEXT: 1: DoStmt (LoopExit)
+// CHECK-NEXT: 2: i
+// CHECK-NEXT: 3: [B3.2]--
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B2
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 2
+// CHECK-NEXT: 4: [B4.2] < [B4.3]
+// CHECK-NEXT: T: do ... while [B4.4]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B6 B3
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1]++
+// CHECK-NEXT: Preds (2): B6 B7
+// CHECK-NEXT: Succs (1): B4
+
+// CHECK: [B6]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: j
+// CHECK-NEXT: 2: [B7.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B7.2] < [B7.3]
+// CHECK-NEXT: T: for (...; [B7.4]; ...)
+// CHECK-NEXT: Preds (2): B2 B8
+// CHECK-NEXT: Succs (2): B5 B1
+
+// CHECK: [B8]
+// CHECK-NEXT: 1: 40
+// CHECK-NEXT: 2: -[B8.1]
+// CHECK-NEXT: 3: int i = -40;
+// CHECK-NEXT: 4: 1
+// CHECK-NEXT: 5: int j = 1;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B7
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void nested_loops2() {
+ int i = -40;
+ for (int j = 1; j < 6; j++) {
+ do {
+ i++;
+ } while (i < 2);
+ i--;
+ }
+}
+
+// CHECK: [B12 (ENTRY)]
+// CHECK-NEXT: Succs (1): B11
+
+// CHECK: [B1]
+// CHECK-NEXT: 1: WhileStmt (LoopExit)
+// CHECK-NEXT: 2: return;
+// CHECK-NEXT: Preds (2): B3 B5
+// CHECK-NEXT: Succs (1): B0
+
+// CHECK: [B2]
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B3]
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B4
+// CHECK-NEXT: Succs (1): B1
+
+// CHECK: [B4]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B4.1]++
+// CHECK-NEXT: 3: i
+// CHECK-NEXT: 4: [B4.3] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 5: 2
+// CHECK-NEXT: 6: [B4.4] % [B4.5]
+// CHECK-NEXT: 7: [B4.6] (ImplicitCastExpr, IntegralToBoolean, _Bool)
+// CHECK-NEXT: T: if [B4.7]
+// CHECK-NEXT: Preds (1): B5
+// CHECK-NEXT: Succs (2): B3 B2
+
+// CHECK: [B5]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B5.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 5
+// CHECK-NEXT: 4: [B5.2] < [B5.3]
+// CHECK-NEXT: T: while [B5.4]
+// CHECK-NEXT: Preds (2): B2 B6
+// CHECK-NEXT: Succs (2): B4 B1
+
+// CHECK: [B6]
+// CHECK-NEXT: 1: ForStmt (LoopExit)
+// CHECK-NEXT: 2: 1
+// CHECK-NEXT: 3: int i = 1;
+// CHECK-NEXT: Preds (2): B8 B10
+// CHECK-NEXT: Succs (1): B5
+
+// CHECK: [B7]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B7.1]++
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B10
+
+// CHECK: [B8]
+// CHECK-NEXT: T: break;
+// CHECK-NEXT: Preds (1): B9
+// CHECK-NEXT: Succs (1): B6
+
+// CHECK: [B9]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B9.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 4
+// CHECK-NEXT: 4: [B9.2] == [B9.3]
+// CHECK-NEXT: T: if [B9.4]
+// CHECK-NEXT: Preds (1): B10
+// CHECK-NEXT: Succs (2): B8 B7
+
+// CHECK: [B10]
+// CHECK-NEXT: 1: i
+// CHECK-NEXT: 2: [B10.1] (ImplicitCastExpr, LValueToRValue, int)
+// CHECK-NEXT: 3: 6
+// CHECK-NEXT: 4: [B10.2] < [B10.3]
+// CHECK-NEXT: T: for (...; [B10.4]; ...)
+// CHECK-NEXT: Preds (2): B7 B11
+// CHECK-NEXT: Succs (2): B9 B6
+
+// CHECK: [B11]
+// CHECK-NEXT: 1: 2
+// CHECK-NEXT: 2: int i = 2;
+// CHECK-NEXT: Preds (1): B12
+// CHECK-NEXT: Succs (1): B10
+
+// CHECK: [B0 (EXIT)]
+// CHECK-NEXT: Preds (1): B1
+void check_break()
+{
+ for(int i = 2; i < 6; i++) {
+ if(i == 4)
+ break;
+ }
+
+ int i = 1;
+ while(i<5){
+ i++;
+ if(i%2)
+ break;
+ }
+
+ return;
+}
diff --git a/test/Analysis/malloc-overflow2.c b/test/Analysis/malloc-overflow2.c
index 2e1b1d4d2b..7c580602e6 100644
--- a/test/Analysis/malloc-overflow2.c
+++ b/test/Analysis/malloc-overflow2.c
@@ -1,4 +1,5 @@
// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -analyzer-checker=alpha.security.MallocOverflow,unix -verify %s
+// RUN: %clang_analyze_cc1 -triple x86_64-unknown-unknown -analyzer-checker=alpha.security.MallocOverflow,unix,optin.portability -DPORTABILITY -verify %s
typedef __typeof__(sizeof(int)) size_t;
extern void *malloc(size_t);
@@ -32,5 +33,8 @@ static int table_build_1(struct table *t) {
}
void *f(int n) {
- return malloc(n * 0 * sizeof(int)); // expected-warning {{Call to 'malloc' has an allocation size of 0 bytes}}
+ return malloc(n * 0 * sizeof(int));
+#ifdef PORTABILITY
+ // expected-warning@-2{{Call to 'malloc' has an allocation size of 0 bytes}}
+#endif
}
diff --git a/test/Analysis/malloc-plist.c b/test/Analysis/malloc-plist.c
index 26aea16045..e2062e8582 100644
--- a/test/Analysis/malloc-plist.c
+++ b/test/Analysis/malloc-plist.c
@@ -421,7 +421,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;p&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -586,7 +586,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;A&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -974,7 +974,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -1376,7 +1376,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -1962,7 +1962,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Use of memory after it is freed</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Use-after-free</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -2524,7 +2524,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;buf&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -2795,7 +2795,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;v&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3144,7 +3144,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Use of memory after it is freed</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Use-after-free</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3309,7 +3309,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;m&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3517,7 +3517,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -3725,7 +3725,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4030,7 +4030,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4335,7 +4335,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4543,7 +4543,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4751,7 +4751,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -4988,7 +4988,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential memory leak</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -5225,7 +5225,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential memory leak</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -5496,7 +5496,7 @@ void testMyMalloc() {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential memory leak</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/malloc.c b/test/Analysis/malloc.c
index d5f2cfedd1..4c364ebd9a 100644
--- a/test/Analysis/malloc.c
+++ b/test/Analysis/malloc.c
@@ -1774,6 +1774,16 @@ int testNoCheckerDataPropogationFromLogicalOpOperandToOpResult(void) {
return ok; // no warning
}
+void (*fnptr)(int);
+void freeIndirectFunctionPtr() {
+ void *p = (void *)fnptr;
+ free(p); // expected-warning {{Argument to free() is a function pointer}}
+}
+
+void freeFunctionPtr() {
+ free((void *)fnptr); // expected-warning {{Argument to free() is a function pointer}}
+}
+
// ----------------------------------------------------------------------------
// False negatives.
diff --git a/test/Analysis/malloc.mm b/test/Analysis/malloc.mm
index f8a43b3b6a..e3daa858be 100644
--- a/test/Analysis/malloc.mm
+++ b/test/Analysis/malloc.mm
@@ -187,7 +187,7 @@ typedef volatile struct {
void *opaque1;
long opaque2;
} OSQueueHead;
-void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
+extern "C" void OSAtomicEnqueue( OSQueueHead *__list, void *__new, size_t __offset) __attribute__((weak_import));
static inline void radar11111210(OSQueueHead *pool) {
void *newItem = malloc(4);
OSAtomicEnqueue(pool, newItem, 4);
diff --git a/test/Analysis/max-nodes-suppress-on-sink.c b/test/Analysis/max-nodes-suppress-on-sink.c
index 8d955b91c1..da1e7bf022 100644
--- a/test/Analysis/max-nodes-suppress-on-sink.c
+++ b/test/Analysis/max-nodes-suppress-on-sink.c
@@ -15,6 +15,8 @@ extern void exit(int) __attribute__ ((__noreturn__));
void clang_analyzer_warnIfReached(void);
+int coin();
+
void test_single_cfg_block_sink() {
void *p = malloc(1); // no-warning (wherever the leak warning may occur here)
@@ -29,3 +31,53 @@ void test_single_cfg_block_sink() {
// the leak report.
exit(0);
}
+
+// A similar test with more complicated control flow before the no-return thing,
+// so that the no-return thing wasn't in the same CFG block.
+void test_more_complex_control_flow_before_sink() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ if (coin())
+ exit(0);
+ else
+ exit(1);
+}
+
+// A loop before the no-return function, to make sure that
+// the dominated-by-sink analysis doesn't hang.
+void test_loop_before_sink(int n) {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ for (int i = 0; i < n; ++i) {
+ }
+ exit(1);
+}
+
+// We're not sure if this is no-return.
+void test_loop_with_sink(int n) {
+ void *p = malloc(1); // expected-warning@+2{{Potential leak of memory}}
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ for (int i = 0; i < n; ++i)
+ if (i == 0)
+ exit(1);
+}
+
+// Handle unreachable blocks correctly.
+void test_unreachable_successor_blocks() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ if (1) // no-crash
+ exit(1);
+}
diff --git a/test/Analysis/max-nodes-suppress-on-sink.cpp b/test/Analysis/max-nodes-suppress-on-sink.cpp
new file mode 100644
index 0000000000..814b302789
--- /dev/null
+++ b/test/Analysis/max-nodes-suppress-on-sink.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_analyze_cc1 -x c++ -fcxx-exceptions -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config max-nodes=12 -verify %s
+
+// Here we test how "suppress on sink" feature of certain bugtypes interacts
+// with reaching analysis limits. See comments in max-nodes-suppress-on-sink.c
+// for more discussion.
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+
+void clang_analyzer_warnIfReached(void);
+
+// Because we don't have a better approach, we currently treat throw as
+// noreturn.
+void test_throw_treated_as_noreturn() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ throw 0;
+}
+
+// FIXME: Handled throws shouldn't be suppressing us!
+void test_handled_throw_treated_as_noreturn() {
+ void *p = malloc(1); // no-warning
+
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+ clang_analyzer_warnIfReached(); // no-warning
+
+ try {
+ throw 0;
+ } catch (int i) {
+ }
+}
diff --git a/test/Analysis/nonnull-global-constants.mm b/test/Analysis/nonnull-global-constants.mm
new file mode 100644
index 0000000000..7900b9dd12
--- /dev/null
+++ b/test/Analysis/nonnull-global-constants.mm
@@ -0,0 +1,103 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+
+// Nullability of const string-like globals, testing
+// NonnullGlobalConstantsChecker.
+
+void clang_analyzer_eval(bool);
+
+@class NSString;
+typedef const struct __CFString *CFStringRef;
+typedef const struct __CFBoolean * CFBooleanRef;
+
+// Global NSString* is non-null.
+extern NSString *const StringConstGlobal;
+void stringConstGlobal() {
+ clang_analyzer_eval(StringConstGlobal); // expected-warning{{TRUE}}
+}
+
+// The logic does not apply to local variables though.
+extern NSString *stringGetter();
+void stringConstLocal() {
+ NSString *const local = stringGetter();
+ clang_analyzer_eval(local); // expected-warning{{UNKNOWN}}
+}
+
+// Global const CFStringRef's are also assumed to be non-null.
+extern const CFStringRef CFStringConstGlobal;
+void cfStringCheckGlobal() {
+ clang_analyzer_eval(CFStringConstGlobal); // expected-warning{{TRUE}}
+}
+
+// But only "const" ones.
+extern CFStringRef CFStringNonConstGlobal;
+void cfStringCheckMutableGlobal() {
+ clang_analyzer_eval(CFStringNonConstGlobal); // expected-warning{{UNKNOWN}}
+}
+
+// char* const is also assumed to be non-null.
+extern const char *const ConstCharStarConst;
+void constCharStarCheckGlobal() {
+ clang_analyzer_eval(ConstCharStarConst); // expected-warning{{TRUE}}
+}
+
+// Pointer value can be mutable.
+extern char *const CharStarConst;
+void charStarCheckGlobal() {
+ clang_analyzer_eval(CharStarConst); // expected-warning{{TRUE}}
+}
+
+// But the pointer itself should be immutable.
+extern char *CharStar;
+void charStartCheckMutableGlobal() {
+ clang_analyzer_eval(CharStar); // expected-warning{{UNKNOWN}}
+}
+
+// Type definitions should also work across typedefs, for pointers:
+typedef char *const str;
+extern str globalStr;
+void charStarCheckTypedef() {
+ clang_analyzer_eval(globalStr); // expected-warning{{TRUE}}
+}
+
+// And for types.
+typedef NSString *const NStr;
+extern NStr globalNSString;
+void NSStringCheckTypedef() {
+ clang_analyzer_eval(globalNSString); // expected-warning{{TRUE}}
+}
+
+// Note that constness could be either inside
+// the var declaration, or in a typedef.
+typedef NSString *NStr2;
+extern const NStr2 globalNSString2;
+void NSStringCheckConstTypedef() {
+ clang_analyzer_eval(globalNSString2); // expected-warning{{TRUE}}
+}
+
+// Nested typedefs should work as well.
+typedef const CFStringRef str1;
+typedef str1 str2;
+extern str2 globalStr2;
+void testNestedTypedefs() {
+ clang_analyzer_eval(globalStr2); // expected-warning{{TRUE}}
+}
+
+// And for NSString *.
+typedef NSString *const nstr1;
+typedef nstr1 nstr2;
+extern nstr2 nglobalStr2;
+void testNestedTypedefsForNSString() {
+ clang_analyzer_eval(nglobalStr2); // expected-warning{{TRUE}}
+}
+
+// And for CFBooleanRefs.
+extern const CFBooleanRef kBool;
+void testNonnullBool() {
+ clang_analyzer_eval(kBool); // expected-warning{{TRUE}}
+}
+
+// And again, only for const one.
+extern CFBooleanRef kBoolMutable;
+void testNonnullNonconstBool() {
+ clang_analyzer_eval(kBoolMutable); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/null-deref-offsets.c b/test/Analysis/null-deref-offsets.c
new file mode 100644
index 0000000000..988cec4985
--- /dev/null
+++ b/test/Analysis/null-deref-offsets.c
@@ -0,0 +1,37 @@
+// RUN: %clang_analyze_cc1 -w -triple i386-apple-darwin10 -analyzer-checker=core,debug.ExprInspection -verify %s
+
+void clang_analyzer_eval(int);
+
+struct S {
+ int x, y;
+ int z[2];
+};
+
+void testOffsets(struct S *s, int coin) {
+ if (s != 0)
+ return;
+
+ // FIXME: Here we are testing the hack that computes offsets to null pointers
+ // as 0 in order to find null dereferences of not-exactly-null pointers,
+ // such as &(s->y) below, which is equal to 4 rather than 0 in run-time.
+
+ // These are indeed null.
+ clang_analyzer_eval(s == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&(s->x) == 0); // expected-warning{{TRUE}}
+
+ // FIXME: These should ideally be true.
+ clang_analyzer_eval(&(s->y) == 4); // expected-warning{{FALSE}}
+ clang_analyzer_eval(&(s->z[0]) == 8); // expected-warning{{FALSE}}
+ clang_analyzer_eval(&(s->z[1]) == 12); // expected-warning{{FALSE}}
+
+ // FIXME: These should ideally be false.
+ clang_analyzer_eval(&(s->y) == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&(s->z[0]) == 0); // expected-warning{{TRUE}}
+ clang_analyzer_eval(&(s->z[1]) == 0); // expected-warning{{TRUE}}
+
+ // But these should still be reported as null dereferences.
+ if (coin)
+ s->y = 5; // expected-warning{{Access to field 'y' results in a dereference of a null pointer (loaded from variable 's')}}
+ else
+ s->z[1] = 6; // expected-warning{{Array access (via field 'z') results in a null pointer dereference}}
+}
diff --git a/test/Analysis/null-deref-path-notes.c b/test/Analysis/null-deref-path-notes.c
new file mode 100644
index 0000000000..a1477a6226
--- /dev/null
+++ b/test/Analysis/null-deref-path-notes.c
@@ -0,0 +1,9 @@
+// RUN: %clang_analyze_cc1 -w -x c -analyzer-checker=core -analyzer-output=text -verify %s
+
+// Avoid the crash when finding the expression for tracking the origins
+// of the null pointer for path notes.
+void pr34373() {
+ int *a = 0; // expected-note{{'a' initialized to a null pointer value}}
+ (a + 0)[0]; // expected-warning{{Array access results in a null pointer dereference}}
+ // expected-note@-1{{Array access results in a null pointer dereference}}
+}
diff --git a/test/Analysis/null-deref-path-notes.cpp b/test/Analysis/null-deref-path-notes.cpp
new file mode 100644
index 0000000000..617f5def15
--- /dev/null
+++ b/test/Analysis/null-deref-path-notes.cpp
@@ -0,0 +1,25 @@
+// RUN: %clang_analyze_cc1 -w -x c++ -analyzer-checker=core -analyzer-output=text -analyzer-eagerly-assume -verify %s
+
+namespace pr34731 {
+int b;
+class c {
+ class B {
+ public:
+ double ***d;
+ B();
+ };
+ void e(double **, int);
+ void f(B &, int &);
+};
+
+// Properly track the null pointer in the array field back to the default
+// constructor of 'h'.
+void c::f(B &g, int &i) {
+ e(g.d[9], i); // expected-warning{{Array access (via field 'd') results in a null pointer dereference}}
+ // expected-note@-1{{Array access (via field 'd') results in a null pointer dereference}}
+ B h, a; // expected-note{{Value assigned to 'h.d'}}
+ a.d == __null; // expected-note{{Assuming the condition is true}}
+ a.d != h.d; // expected-note{{Assuming pointer value is null}}
+ f(h, b); // expected-note{{Calling 'c::f'}}
+}
+}
diff --git a/test/Analysis/null-deref-path-notes.m b/test/Analysis/null-deref-path-notes.m
index 242b5daa9b..39cf9c79f3 100644
--- a/test/Analysis/null-deref-path-notes.m
+++ b/test/Analysis/null-deref-path-notes.m
@@ -50,6 +50,23 @@ void repeatedStores(int coin) {
*p = 1; // expected-warning{{Dereference of null pointer}} expected-note{{Dereference of null pointer}}
}
+@interface WithArrayPtr
+- (void) useArray;
+@end
+
+@implementation WithArrayPtr {
+@public int *p;
+}
+- (void)useArray {
+ p[1] = 2; // expected-warning{{Array access (via ivar 'p') results in a null pointer dereference}}
+ // expected-note@-1{{Array access (via ivar 'p') results in a null pointer dereference}}
+}
+@end
+
+void testWithArrayPtr(WithArrayPtr *w) {
+ w->p = 0; // expected-note{{Null pointer value stored to 'p'}}
+ [w useArray]; // expected-note{{Calling 'useArray'}}
+}
// CHECK: <key>diagnostics</key>
// CHECK-NEXT: <array>
@@ -801,4 +818,227 @@ void repeatedStores(int coin) {
// CHECK-NEXT: <key>file</key><integer>0</integer>
// CHECK-NEXT: </dict>
// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Null pointer value stored to &apos;p&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>67</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>68</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Calling &apos;useArray&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Calling &apos;useArray&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testWithArrayPtr&apos;</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Entered call from &apos;testWithArrayPtr&apos;</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>60</integer>
+// CHECK-NEXT: <key>col</key><integer>1</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Array access (via ivar &apos;p&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Array access (via ivar &apos;p&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Array access (via ivar &apos;p&apos;) results in a null pointer dereference</string>
+// CHECK-NEXT: <key>category</key><string>Logic error</string>
+// CHECK-NEXT: <key>type</key><string>Dereference of null pointer</string>
+// CHECK-NEXT: <key>check_name</key><string>core.NullDereference</string>
+// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>fb0ad1e4e3090d9834d542eb54bc9d2e</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>useArray</string>
+// CHECK-NEXT: <key>issue_hash_function_offset</key><string>1</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>61</integer>
+// CHECK-NEXT: <key>col</key><integer>8</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c
index 6ef99ae473..c46ca6c52a 100644
--- a/test/Analysis/null-deref-ps-region.c
+++ b/test/Analysis/null-deref-ps-region.c
@@ -1,6 +1,11 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s
-// expected-no-diagnostics
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,unix,alpha.unix -std=gnu99 -analyzer-store=region -verify %s
+#include "Inputs/system-header-simulator.h"
+
+typedef __typeof(sizeof(int)) size_t;
+void *memset(void *__s, int __c, size_t __n);
+void *malloc(size_t __size);
+void free(void *__ptr);
// The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may
// also be live roots.
@@ -13,3 +18,55 @@ void f14(int *a) {
i = *p; // no-warning
}
}
+
+void foo() {
+ int *x = malloc(sizeof(int));
+ memset(x, 0, sizeof(int));
+ int n = 1 / *x; // FIXME: no-warning
+ free(x);
+}
+
+void bar() {
+ int *x = malloc(sizeof(int));
+ memset(x, 0, 1);
+ int n = 1 / *x; // no-warning
+ free(x);
+}
+
+void testConcreteNull() {
+ int *x = 0;
+ memset(x, 0, 1); // expected-warning {{Null pointer argument in call to memory set function}}
+}
+
+void testStackArray() {
+ char buf[13];
+ memset(buf, 0, 1); // no-warning
+}
+
+void testHeapSymbol() {
+ char *buf = (char *)malloc(13);
+ memset(buf, 0, 1); // no-warning
+ free(buf);
+}
+
+void testStackArrayOutOfBound() {
+ char buf[1];
+ memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+}
+
+void testHeapSymbolOutOfBound() {
+ char *buf = (char *)malloc(1);
+ memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}}
+ free(buf);
+}
+
+void testStackArraySameSize() {
+ char buf[1];
+ memset(buf, 0, sizeof(buf)); // no-warning
+}
+
+void testHeapSymbolSameSize() {
+ char *buf = (char *)malloc(1);
+ memset(buf, 0, 1); // no-warning
+ free(buf);
+}
diff --git a/test/Analysis/null-deref-ps.c b/test/Analysis/null-deref-ps.c
index 5dee308a00..d0e1f9f5cc 100644
--- a/test/Analysis/null-deref-ps.c
+++ b/test/Analysis/null-deref-ps.c
@@ -1,5 +1,5 @@
-// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -analyzer-purge=none -verify %s -Wno-error=return-type
-// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -verify %s -Wno-error=return-type
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -Wno-tautological-constant-compare -Wtautological-unsigned-zero-compare -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -analyzer-purge=none -verify %s -Wno-error=return-type
+// RUN: %clang_analyze_cc1 -triple i386-apple-darwin10 -Wno-tautological-constant-compare -Wtautological-unsigned-zero-compare -analyzer-checker=core,deadcode,alpha.core -std=gnu99 -analyzer-store=region -verify %s -Wno-error=return-type
typedef unsigned uintptr_t;
diff --git a/test/Analysis/nullability-notes.m b/test/Analysis/nullability-notes.m
new file mode 100644
index 0000000000..c93aa02c42
--- /dev/null
+++ b/test/Analysis/nullability-notes.m
@@ -0,0 +1,204 @@
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=text -verify %s
+// RUN: %clang_analyze_cc1 -fblocks -analyzer-checker=core,nullability.NullPassedToNonnull,nullability.NullReturnedFromNonnull,nullability.NullablePassedToNonnull,nullability.NullableReturnedFromNonnull,nullability.NullableDereferenced -analyzer-output=plist -analyzer-config path-diagnostics-alternate=true -o %t.plist %s
+// RUN: FileCheck --input-file=%t.plist %s
+
+#include "Inputs/system-header-simulator-for-nullability.h"
+
+void takesNonnull(NSObject *_Nonnull y);
+
+@interface ClassWithProperties: NSObject
+@property(copy, nullable) NSObject *x; // plist check ensures no control flow piece from here to 'self.x'.
+-(void) method;
+@end;
+@implementation ClassWithProperties
+-(void) method {
+ // no-crash
+ NSObject *x = self.x; // expected-note{{Nullability 'nullable' is inferred}}
+ takesNonnull(x); // expected-warning{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+ // expected-note@-1{{Nullable pointer is passed to a callee that requires a non-null 1st parameter}}
+}
+@end
+
+// CHECK: <key>diagnostics</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>path</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>1</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Nullability &apos;nullable&apos; is inferred</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Nullability &apos;nullable&apos; is inferred</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>22</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>control</string>
+// CHECK-NEXT: <key>edges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>start</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>16</integer>
+// CHECK-NEXT: <key>col</key><integer>10</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>end</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>14</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>kind</key><string>event</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <key>ranges</key>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <array>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>16</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>depth</key><integer>0</integer>
+// CHECK-NEXT: <key>extended_message</key>
+// CHECK-NEXT: <string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
+// CHECK-NEXT: <key>message</key>
+// CHECK-NEXT: <string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
+// CHECK-NEXT: <key>description</key><string>Nullable pointer is passed to a callee that requires a non-null 1st parameter</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
+// CHECK-NEXT: <key>type</key><string>Nullability</string>
+// CHECK-NEXT: <key>check_name</key><string>nullability.NullPassedToNonnull</string>
+// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
+// CHECK-NEXT: <key>issue_hash_content_of_line_in_context</key><string>b6bc8126de8e6eb3375483a656fe858d</string>
+// CHECK-NEXT: <key>issue_context_kind</key><string>Objective-C method</string>
+// CHECK-NEXT: <key>issue_context</key><string>method</string>
+// CHECK-NEXT: <key>issue_hash_function_offset</key><string>3</string>
+// CHECK-NEXT: <key>location</key>
+// CHECK-NEXT: <dict>
+// CHECK-NEXT: <key>line</key><integer>17</integer>
+// CHECK-NEXT: <key>col</key><integer>3</integer>
+// CHECK-NEXT: <key>file</key><integer>0</integer>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </dict>
+// CHECK-NEXT: </array>
diff --git a/test/Analysis/nullptr.cpp b/test/Analysis/nullptr.cpp
index 229ad7bbb5..b3e61c9def 100644
--- a/test/Analysis/nullptr.cpp
+++ b/test/Analysis/nullptr.cpp
@@ -1,11 +1,12 @@
-// RUN: %clang_analyze_cc1 -std=c++11 -Wno-conversion-null -analyzer-checker=core,debug.ExprInspection -analyzer-store region -verify %s
+// RUN: %clang_analyze_cc1 -std=c++11 -Wno-conversion-null -analyzer-checker=core,debug.ExprInspection -analyzer-store region -analyzer-output=text -verify %s
void clang_analyzer_eval(int);
// test to see if nullptr is detected as a null pointer
void foo1(void) {
- char *np = nullptr;
+ char *np = nullptr; // expected-note{{'np' initialized to a null pointer value}}
*np = 0; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
}
// check if comparing nullptr to nullptr is detected properly
@@ -23,10 +24,11 @@ void foo3(void) {
struct foo {
int a, f;
};
- char *np = nullptr;
+ char *np = nullptr; // expected-note{{'np' initialized to a null pointer value}}
// casting a nullptr to anything should be caught eventually
- int *ip = &(((struct foo *)np)->f);
+ int *ip = &(((struct foo *)np)->f); // expected-note{{'ip' initialized to a null pointer value}}
*ip = 0; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
// should be error here too, but analysis gets stopped
// *np = 0;
}
@@ -49,16 +51,31 @@ int pr10372(void *& x) {
}
void zoo1() {
- char **p = 0;
+ char **p = 0; // expected-note{{'p' initialized to a null pointer value}}
delete *(p + 0); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
+}
+
+void zoo1backwards() {
+ char **p = 0; // expected-note{{'p' initialized to a null pointer value}}
+ delete *(0 + p); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
+}
+
+typedef __INTPTR_TYPE__ intptr_t;
+void zoo1multiply() {
+ char **p = 0; // FIXME-should-be-note:{{'p' initialized to a null pointer value}}
+ delete *((char **)((intptr_t)p * 2)); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
}
void zoo2() {
int **a = 0;
- int **b = 0;
+ int **b = 0; // expected-note{{'b' initialized to a null pointer value}}
asm ("nop"
:"=r"(*a)
:"0"(*b) // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
);
}
@@ -70,17 +87,19 @@ int exprWithCleanups() {
int a;
};
- int *x = 0;
+ int *x = 0; // expected-note{{'x' initialized to a null pointer value}}
return S(*x).a; // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
}
int materializeTempExpr() {
- int *n = 0;
+ int *n = 0; // expected-note{{'n' initialized to a null pointer value}}
struct S {
int a;
S(int i): a(i) {}
};
const S &s = S(*n); // expected-warning{{Dereference of null pointer}}
+ // expected-note@-1{{Dereference of null pointer}}
return s.a;
}
@@ -98,6 +117,7 @@ struct X {
void invokeF(X* x) {
x->f(); // expected-warning{{Called C++ object pointer is null}}
+ // expected-note@-1{{Called C++ object pointer is null}}
}
struct Type {
@@ -105,26 +125,41 @@ struct Type {
};
void shouldNotCrash() {
- decltype(nullptr) p;
- if (getSymbol())
- invokeF(p); // expected-warning{{1st function call argument is an uninit}}
- if (getSymbol())
- invokeF(nullptr);
- if (getSymbol()) {
- X *x = Type().x;
+ decltype(nullptr) p; // expected-note{{'p' declared without an initial value}}
+ if (getSymbol()) // expected-note {{Assuming the condition is false}}
+ // expected-note@-1{{Taking false branch}}
+ // expected-note@-2{{Assuming the condition is false}}
+ // expected-note@-3{{Taking false branch}}
+ // expected-note@-4{{Assuming the condition is true}}
+ // expected-note@-5{{Taking true branch}}
+ invokeF(p); // expected-warning{{1st function call argument is an uninitialized value}}
+ // expected-note@-1{{1st function call argument is an uninitialized value}}
+ if (getSymbol()) // expected-note {{Assuming the condition is false}}
+ // expected-note@-1{{Taking false branch}}
+ // expected-note@-2{{Assuming the condition is true}}
+ // expected-note@-3{{Taking true branch}}
+ invokeF(nullptr); // expected-note {{Calling 'invokeF'}}
+ // expected-note@-1{{Passing null pointer value via 1st parameter 'x'}}
+ if (getSymbol()) { // expected-note {{Assuming the condition is true}}
+ // expected-note@-1{{Taking true branch}}
+ X *x = Type().x; // expected-note{{'x' initialized to a null pointer value}}
x->f(); // expected-warning{{Called C++ object pointer is null}}
+ // expected-note@-1{{Called C++ object pointer is null}}
}
}
void f(decltype(nullptr) p) {
int *q = nullptr;
clang_analyzer_eval(p == 0); // expected-warning{{TRUE}}
+ // expected-note@-1{{TRUE}}
clang_analyzer_eval(q == 0); // expected-warning{{TRUE}}
+ // expected-note@-1{{TRUE}}
}
decltype(nullptr) returnsNullPtrType();
void fromReturnType() {
((X *)returnsNullPtrType())->f(); // expected-warning{{Called C++ object pointer is null}}
+ // expected-note@-1{{Called C++ object pointer is null}}
}
#define AS_ATTRIBUTE __attribute__((address_space(256)))
diff --git a/test/Analysis/objc-boxing.m b/test/Analysis/objc-boxing.m
index 963374b3ef..66f24ddf77 100644
--- a/test/Analysis/objc-boxing.m
+++ b/test/Analysis/objc-boxing.m
@@ -5,6 +5,16 @@ void clang_analyzer_eval(int);
typedef signed char BOOL;
typedef long NSInteger;
typedef unsigned long NSUInteger;
+
+@protocol NSObject
+@end
+@interface NSObject <NSObject> {}
+@end
+@protocol NSCopying
+@end
+@protocol NSCoding
+@end
+
@interface NSString @end
@interface NSString (NSStringExtensionMethods)
+ (id)stringWithUTF8String:(const char *)nullTerminatedCString;
@@ -28,7 +38,15 @@ typedef unsigned long NSUInteger;
+ (NSNumber *)numberWithUnsignedInteger:(NSUInteger)value ;
@end
+@interface NSValue : NSObject <NSCopying, NSCoding>
+- (void)getValue:(void *)value;
++ (NSValue *)valueWithBytes:(const void *)value
+ objCType:(const char *)type;
+@end
+typedef typeof(sizeof(int)) size_t;
+extern void *malloc(size_t);
+extern void free(void *);
extern char *strdup(const char *str);
id constant_string() {
@@ -39,6 +57,23 @@ id dynamic_string() {
return @(strdup("boxed dynamic string")); // expected-warning{{Potential memory leak}}
}
+typedef struct __attribute__((objc_boxable)) {
+ const char *str;
+} BoxableStruct;
+
+id leak_within_boxed_struct() {
+ BoxableStruct bs;
+ bs.str = strdup("dynamic string"); // The duped string shall be owned by val.
+ NSValue *val = @(bs); // no-warning
+ return val;
+}
+
+id leak_of_boxed_struct() {
+ BoxableStruct *bs = malloc(sizeof(BoxableStruct)); // The pointer stored in bs isn't owned by val.
+ NSValue *val = @(*bs); // expected-warning{{Potential leak of memory pointed to by 'bs'}}
+ return val;
+}
+
id const_char_pointer(int *x) {
if (x)
return @(3);
diff --git a/test/Analysis/objc-encode.m b/test/Analysis/objc-encode.m
new file mode 100644
index 0000000000..b2379e96d9
--- /dev/null
+++ b/test/Analysis/objc-encode.m
@@ -0,0 +1,9 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.ExprInspection -verify %s
+// expected-no-diagnostics
+
+void clang_analyzer_eval(int);
+
+// rdar://problem/34831581: Used to crash.
+void foo(void) {
+ char buf1[] = @encode(int **);
+}
diff --git a/test/Analysis/objc-for.m b/test/Analysis/objc-for.m
index 41709bee35..f1d0cf18d6 100644
--- a/test/Analysis/objc-for.m
+++ b/test/Analysis/objc-for.m
@@ -1,6 +1,7 @@
// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.cocoa.Loops,debug.ExprInspection -verify %s
void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
#define nil ((id)0)
@@ -20,11 +21,13 @@ typedef unsigned long NSUInteger;
@interface NSArray : NSObject <NSFastEnumeration>
- (NSUInteger)count;
- (NSEnumerator *)objectEnumerator;
++ (NSArray *)arrayWithObjects:(const id [])objects count:(NSUInteger)count;
@end
@interface NSDictionary : NSObject <NSFastEnumeration>
- (NSUInteger)count;
- (id)objectForKey:(id)key;
++ (id)dictionaryWithObjects:(const id [])objects forKeys:(const id /* <NSCopying> */ [])keys count:(NSUInteger)count;
@end
@interface NSDictionary (SomeCategory)
@@ -324,3 +327,19 @@ void protocolMethods(NSMutableArray *array) {
for (id key in array)
clang_analyzer_eval(0); // expected-warning{{FALSE}}
}
+
+NSArray *globalArray;
+NSDictionary *globalDictionary;
+void boxedArrayEscape(NSMutableArray *array) {
+ if ([array count])
+ return;
+ globalArray = @[array];
+ for (id key in array)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+
+ if ([array count])
+ return;
+ globalDictionary = @{ @"array" : array };
+ for (id key in array)
+ clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
diff --git a/test/Analysis/plist-macros.cpp b/test/Analysis/plist-macros.cpp
index 594cfdc6ef..18d3ce11e6 100644
--- a/test/Analysis/plist-macros.cpp
+++ b/test/Analysis/plist-macros.cpp
@@ -218,7 +218,7 @@ void test2(int *p) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Memory allocated by malloc() should be deallocated by free(), not &apos;delete&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Bad deallocator</string>
// CHECK-NEXT: <key>check_name</key><string>unix.MismatchedDeallocator</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
@@ -315,7 +315,7 @@ void test2(int *p) {
// CHECK-NEXT: </dict>
// CHECK-NEXT: </array>
// CHECK-NEXT: <key>description</key><string>Potential leak of memory pointed to by &apos;x&apos;</string>
-// CHECK-NEXT: <key>category</key><string>Memory Error</string>
+// CHECK-NEXT: <key>category</key><string>Memory error</string>
// CHECK-NEXT: <key>type</key><string>Memory leak</string>
// CHECK-NEXT: <key>check_name</key><string>unix.Malloc</string>
// CHECK-NEXT: <!-- This hash is experimental and going to change! -->
diff --git a/test/Analysis/pointer-arithmetic.c b/test/Analysis/pointer-arithmetic.c
new file mode 100644
index 0000000000..575dfffc01
--- /dev/null
+++ b/test/Analysis/pointer-arithmetic.c
@@ -0,0 +1,30 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s
+
+int test1() {
+ int *p = (int *)sizeof(int);
+ p -= 1;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test2() {
+ int *p = (int *)sizeof(int);
+ p -= 2;
+ p += 1;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test3() {
+ int *p = (int *)sizeof(int);
+ p++;
+ p--;
+ p--;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
+
+int test4() {
+ // This is a special case where pointer arithmetic is not calculated to
+ // preserve useful warnings on dereferences of null pointers.
+ int *p = 0;
+ p += 1;
+ return *p; // expected-warning {{Dereference of null pointer}}
+}
diff --git a/test/Analysis/properties.m b/test/Analysis/properties.m
index 542a339cd6..e792bb2e6b 100644
--- a/test/Analysis/properties.m
+++ b/test/Analysis/properties.m
@@ -987,5 +987,21 @@ void testOpaqueConsistency(OpaqueIntWrapper *w) {
}
@end
+
+@interface Wrapper
+@property(nonatomic, readonly) int value;
+@end
+
+@implementation Wrapper
+@synthesize value;
+@end
+
+void testNoCrashWhenAccessPropertyAndThereAreNoDirectBindingsAtAll() {
+ union {
+ Wrapper *wrapper;
+ } u = { 0 };
+ [u.wrapper value];
+}
+
#endif // non-ARC
diff --git a/test/Analysis/pthreadlock.c b/test/Analysis/pthreadlock.c
index 9886817252..56a92d7d4d 100644
--- a/test/Analysis/pthreadlock.c
+++ b/test/Analysis/pthreadlock.c
@@ -176,6 +176,42 @@ ok22(void) {
pthread_mutex_unlock(pmtx); // no-warning
}
+void ok23(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_destroy(&mtx1); // no-warning
+}
+
+void ok24(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+}
+
+void ok25(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+}
+
+void ok26(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+}
+
+void ok27(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ else
+ pthread_mutex_init(&mtx1, NULL); // no-warning
+}
+
+void ok28(void) {
+ if (pthread_mutex_destroy(&mtx1) != 0) { // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ pthread_mutex_destroy(&mtx1); // no-warning
+ }
+}
void
bad1(void)
@@ -392,3 +428,46 @@ bad26(void)
pthread_mutex_unlock(&mtx1); // no-warning
pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
}
+
+void bad27(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ int ret = pthread_mutex_destroy(&mtx1); // no-warning
+ if (ret != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ else
+ pthread_mutex_unlock(&mtx1); // expected-warning{{This lock has already been destroyed}}
+}
+
+void bad28(void) {
+ pthread_mutex_unlock(&mtx1); // no-warning
+ int ret = pthread_mutex_destroy(&mtx1); // no-warning
+ if (ret != 0) // no-warning
+ pthread_mutex_lock(&mtx1); // no-warning
+ else
+ pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been destroyed}}
+}
+
+void bad29(void) {
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
+ else
+ pthread_mutex_init(&mtx1, NULL); // no-warning
+}
+
+void bad30(void) {
+ pthread_mutex_lock(&mtx1); // no-warning
+ pthread_mutex_unlock(&mtx1); // no-warning
+ if (pthread_mutex_destroy(&mtx1) != 0) // no-warning
+ pthread_mutex_init(&mtx1, NULL); // expected-warning{{This lock has already been initialized}}
+ else
+ pthread_mutex_destroy(&mtx1); // expected-warning{{This lock has already been destroyed}}
+}
+
+void bad31(void) {
+ int ret = pthread_mutex_destroy(&mtx1); // no-warning
+ pthread_mutex_lock(&mtx1); // expected-warning{{This lock has already been destroyed}}
+ if (ret != 0)
+ pthread_mutex_lock(&mtx1);
+}
diff --git a/test/Analysis/ptr-arith.c b/test/Analysis/ptr-arith.c
index b78ec503a1..93cb4ee9a6 100644
--- a/test/Analysis/ptr-arith.c
+++ b/test/Analysis/ptr-arith.c
@@ -342,3 +342,8 @@ void negativeIndex(char *str) {
clang_analyzer_eval(*ptr3 == 'a'); // expected-warning{{UNKNOWN}}
}
+void test_no_crash_on_pointer_to_label() {
+ char *a = &&label;
+ a[0] = 0;
+label:;
+}
diff --git a/test/Analysis/ptr-arith.cpp b/test/Analysis/ptr-arith.cpp
index e1860f4268..1eec83c643 100644
--- a/test/Analysis/ptr-arith.cpp
+++ b/test/Analysis/ptr-arith.cpp
@@ -98,3 +98,22 @@ void checkMultiDimansionalArray() {
int a[5][5];
*(*(a+1)+2) = 2;
}
+
+unsigned ptrSubtractionNoCrash(char *Begin, char *End) {
+ auto N = End - Begin;
+ if (Begin)
+ return 0;
+ return N;
+}
+
+// Bug 34309
+bool ptrAsIntegerSubtractionNoCrash(__UINTPTR_TYPE__ x, char *p) {
+ __UINTPTR_TYPE__ y = (__UINTPTR_TYPE__)p - 1;
+ return y == x;
+}
+
+// Bug 34374
+bool integerAsPtrSubtractionNoCrash(char *p, __UINTPTR_TYPE__ m) {
+ auto n = p - reinterpret_cast<char*>((__UINTPTR_TYPE__)1);
+ return n == m;
+}
diff --git a/test/Analysis/reference.cpp b/test/Analysis/reference.cpp
index b323b96661..c269dd7bad 100644
--- a/test/Analysis/reference.cpp
+++ b/test/Analysis/reference.cpp
@@ -117,6 +117,11 @@ void testRetroactiveNullReference(int *x) {
y = 5; // expected-warning{{Dereference of null pointer}}
}
+namespace TestReferenceAddress {
+struct S { int &x; };
+S getS();
+S *getSP();
+
void testReferenceAddress(int &x) {
// FIXME: Move non-zero reference assumption out of RangeConstraintManager.cpp:422
#ifdef ANALYZER_CM_Z3
@@ -127,23 +132,19 @@ void testReferenceAddress(int &x) {
clang_analyzer_eval(&ref() != 0); // expected-warning{{TRUE}}
#endif
- struct S { int &x; };
-
- extern S getS();
#ifdef ANALYZER_CM_Z3
clang_analyzer_eval(&getS().x != 0); // expected-warning{{UNKNOWN}}
#else
clang_analyzer_eval(&getS().x != 0); // expected-warning{{TRUE}}
#endif
- extern S *getSP();
#ifdef ANALYZER_CM_Z3
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{UNKNOWN}}
#else
clang_analyzer_eval(&getSP()->x != 0); // expected-warning{{TRUE}}
#endif
}
-
+}
void testFunctionPointerReturn(void *opaque) {
typedef int &(*RefFn)();
diff --git a/test/Analysis/retain-release-inline.m b/test/Analysis/retain-release-inline.m
index 0cde2c1cf5..4fe6bca4a4 100644
--- a/test/Analysis/retain-release-inline.m
+++ b/test/Analysis/retain-release-inline.m
@@ -12,7 +12,7 @@
//
// It includes the basic definitions for the test cases below.
//===----------------------------------------------------------------------===//
-
+#define NULL 0
typedef unsigned int __darwin_natural_t;
typedef unsigned long uintptr_t;
typedef unsigned int uint32_t;
@@ -267,6 +267,10 @@ typedef NSUInteger NSStringEncoding;
extern CFStringRef CFStringCreateWithCStringNoCopy(CFAllocatorRef alloc, const char *cStr, CFStringEncoding encoding, CFAllocatorRef contentsDeallocator);
+typedef struct {
+ int ref;
+} isl_basic_map;
+
//===----------------------------------------------------------------------===//
// Test cases.
//===----------------------------------------------------------------------===//
@@ -285,6 +289,7 @@ void test() {
foo(s);
bar(s);
}
+
void test_neg() {
NSString *s = [[NSString alloc] init]; // no-warning
foo(s);
@@ -294,6 +299,89 @@ void test_neg() {
bar(s);
}
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_cow(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap);
+void free(void *);
+
+void callee_side_parameter_checking_leak(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) { // expected-warning {{Potential leak of an object}}
+}
+
+// As 'isl_basic_map_free' is annotated with 'rc_ownership_trusted_implementation', RetainCountChecker trusts its
+// implementation and doesn't analyze its body. If the annotation 'rc_ownership_trusted_implementation' is removed,
+// a leak warning is raised by RetainCountChecker as the analyzer is unable to detect a decrement in the reference
+// count of 'bmap' along the path in 'isl_basic_map_free' assuming the predicate of the second 'if' branch to be
+// true or assuming both the predicates in the function to be false.
+__attribute__((annotate("rc_ownership_trusted_implementation"))) isl_basic_map *isl_basic_map_free(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ if (!bmap)
+ return NULL;
+
+ if (--bmap->ref > 0)
+ return NULL;
+
+ free(bmap);
+ return NULL;
+}
+
+// As 'isl_basic_map_copy' is annotated with 'rc_ownership_trusted_implementation', RetainCountChecker trusts its
+// implementation and doesn't analyze its body. If that annotation is removed, a 'use-after-release' warning might
+// be raised by RetainCountChecker as the pointer which is passed as an argument to this function and the pointer
+// which is returned from the function point to the same memory location.
+__attribute__((annotate("rc_ownership_trusted_implementation"))) __attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_copy(isl_basic_map *bmap) {
+ if (!bmap)
+ return NULL;
+
+ bmap->ref++;
+ return bmap;
+}
+
+void test_use_after_release_with_trusted_implementation_annotate_attribute(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ // After this call, 'bmap' has a +1 reference count.
+ bmap = isl_basic_map_cow(bmap);
+ // After the call to 'isl_basic_map_copy', 'bmap' has a +1 reference count.
+ isl_basic_map *temp = isl_basic_map_cow(isl_basic_map_copy(bmap));
+ // After this call, 'bmap' has a +0 reference count.
+ isl_basic_map *temp2 = isl_basic_map_cow(bmap); // no-warning
+ isl_basic_map_free(temp2);
+ isl_basic_map_free(temp);
+}
+
+void test_leak_with_trusted_implementation_annotate_attribute(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ // After this call, 'bmap' has a +1 reference count.
+ bmap = isl_basic_map_cow(bmap); // no-warning
+ // After this call, 'bmap' has a +0 reference count.
+ isl_basic_map_free(bmap);
+}
+
+void callee_side_parameter_checking_incorrect_rc_decrement(isl_basic_map *bmap) {
+ isl_basic_map_free(bmap); // expected-warning {{Incorrect decrement of the reference count}}
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *callee_side_parameter_checking_return_notowned_object(isl_basic_map *bmap) {
+ return bmap; // expected-warning {{Object with a +0 retain count returned to caller where a +1 (owning) retain count is expected}}
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *callee_side_parameter_checking_assign_consumed_parameter_leak_return(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap1, __attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap2) { // expected-warning {{Potential leak of an object}}
+ bmap1 = bmap2;
+ isl_basic_map_free(bmap2);
+ return bmap1;
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *callee_side_parameter_checking_assign_consumed_parameter_leak(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap1, __attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap2) { // expected-warning {{Potential leak of an object}}
+ bmap1 = bmap2;
+ isl_basic_map_free(bmap1);
+ return bmap2;
+}
+
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *error_path_leak(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap1, __attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap2) { // expected-warning {{Potential leak of an object}}
+ bmap1 = isl_basic_map_cow(bmap1);
+ if (!bmap1 || !bmap2)
+ goto error;
+
+ isl_basic_map_free(bmap2);
+ return bmap1;
+error:
+ return isl_basic_map_free(bmap1);
+}
+
//===----------------------------------------------------------------------===//
// Test returning retained and not-retained values.
//===----------------------------------------------------------------------===//
diff --git a/test/Analysis/retain-release-safe.c b/test/Analysis/retain-release-safe.c
new file mode 100644
index 0000000000..de74355242
--- /dev/null
+++ b/test/Analysis/retain-release-safe.c
@@ -0,0 +1,72 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,osx.coreFoundation.CFRetainRelease,osx.cocoa.RetainCount -verify %s
+
+#pragma clang arc_cf_code_audited begin
+typedef const void * CFTypeRef;
+extern CFTypeRef CFRetain(CFTypeRef cf);
+extern void CFRelease(CFTypeRef cf);
+#pragma clang arc_cf_code_audited end
+
+#define CF_RETURNS_RETAINED __attribute__((cf_returns_retained))
+#define CF_CONSUMED __attribute__((cf_consumed))
+
+extern CFTypeRef CFCreate() CF_RETURNS_RETAINED;
+
+// A "safe" variant of CFRetain that doesn't crash when a null pointer is
+// retained. This is often defined by users in a similar manner. The
+// CF_RETURNS_RETAINED annotation is misleading here, because the function
+// is not supposed to return an object with a +1 retain count. Instead, it
+// is supposed to return an object with +(N+1) retain count, where N is
+// the original retain count of 'cf'. However, there is no good annotation
+// to use in this case, and it is pointless to provide such annotation
+// because the only use cases would be CFRetain and SafeCFRetain.
+// So instead we teach the analyzer to be able to accept such code
+// and ignore the misplaced annotation.
+CFTypeRef SafeCFRetain(CFTypeRef cf) CF_RETURNS_RETAINED {
+ if (cf) {
+ return CFRetain(cf);
+ }
+ return cf;
+}
+
+// A "safe" variant of CFRelease that doesn't crash when a null pointer is
+// released. The CF_CONSUMED annotation seems reasonable here.
+void SafeCFRelease(CFTypeRef CF_CONSUMED cf) {
+ if (cf)
+ CFRelease(cf); // no-warning (when inlined)
+}
+
+void escape(CFTypeRef cf);
+
+void makeSureTestsWork() {
+ CFTypeRef cf = CFCreate();
+ CFRelease(cf);
+ CFRelease(cf); // expected-warning{{Reference-counted object is used after it is released}}
+}
+
+// Make sure we understand that the second SafeCFRetain doesn't return an
+// object with +1 retain count, which we won't be able to release twice.
+void falseOverrelease(CFTypeRef cf) {
+ SafeCFRetain(cf);
+ SafeCFRetain(cf);
+ SafeCFRelease(cf);
+ SafeCFRelease(cf); // no-warning after inlining this.
+}
+
+// Regular CFRelease() should behave similarly.
+void sameWithNormalRelease(CFTypeRef cf) {
+ SafeCFRetain(cf);
+ SafeCFRetain(cf);
+ CFRelease(cf);
+ CFRelease(cf); // no-warning
+}
+
+// Make sure we understand that the second SafeCFRetain doesn't return an
+// object with +1 retain count, which would no longer be owned by us after
+// it escapes to escape() and released once.
+void falseReleaseNotOwned(CFTypeRef cf) {
+ SafeCFRetain(cf);
+ SafeCFRetain(cf);
+ escape(cf);
+ SafeCFRelease(cf);
+ SafeCFRelease(cf); // no-warning after inlining this.
+}
diff --git a/test/Analysis/retain-release.m b/test/Analysis/retain-release.m
index 39a3baa896..a1cc62cb35 100644
--- a/test/Analysis/retain-release.m
+++ b/test/Analysis/retain-release.m
@@ -325,6 +325,9 @@ typedef const struct __CFUUID * CFUUIDRef;
extern
void *CFPlugInInstanceCreate(CFAllocatorRef allocator, CFUUIDRef factoryUUID, CFUUIDRef typeUUID);
+typedef struct {
+ int ref;
+} isl_basic_map;
//===----------------------------------------------------------------------===//
// Test cases.
@@ -574,6 +577,14 @@ void f17(int x, CFTypeRef p) {
}
}
+__attribute__((annotate("rc_ownership_returns_retained"))) isl_basic_map *isl_basic_map_cow(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap);
+
+// Test custom diagnostics for generalized objects.
+void f18(__attribute__((annotate("rc_ownership_consumed"))) isl_basic_map *bmap) {
+ // After this call, 'bmap' has a +1 reference count.
+ bmap = isl_basic_map_cow(bmap); // expected-warning {{Potential leak of an object}}
+}
+
// Test basic tracking of ivars associated with 'self'. For the retain/release
// checker we currently do not want to flag leaks associated with stores
// of tracked objects to ivars.
@@ -1447,7 +1458,7 @@ typedef NSString* MyStringTy;
+ (void) consume2:(id) CF_CONSUMED x;
@end
-static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' attribute only applies to functions and methods}}
+static int ownership_attribute_doesnt_go_here NS_RETURNS_RETAINED; // expected-warning{{'ns_returns_retained' only applies to function types; type here is 'int'}}
void test_attr_1(TestOwnershipAttr *X) {
NSString *str = [X returnsAnOwnedString]; // expected-warning{{leak}}
@@ -1776,15 +1787,15 @@ CFArrayRef camel_copymachine() {
// rdar://problem/8024350
@protocol F18P
-- (id) clone;
+- (id) clone; // expected-note 2 {{method declared here}}
@end
@interface F18 : NSObject<F18P> @end
@interface F18(Cat)
-- (id) clone NS_RETURNS_RETAINED;
+- (id) clone NS_RETURNS_RETAINED; // expected-warning {{overriding method has mismatched ns_returns_retained attributes}}
@end
@implementation F18
-- (id) clone {
+- (id) clone { // expected-warning {{overriding method has mismatched ns_returns_retained attributes}}
return [F18 alloc];
}
@end
diff --git a/test/Analysis/retain-release.mm b/test/Analysis/retain-release.mm
index c9817005c2..ac83c1a48e 100644
--- a/test/Analysis/retain-release.mm
+++ b/test/Analysis/retain-release.mm
@@ -461,3 +461,12 @@ void radar13722286::PrepareBitmap() {
}
}
+// rdar://34210609
+void _() { _(); }; // no-warning
+
+// Do not assume that IOBSDNameMatching increments a reference counter,
+// unless return type is CFMutableDictionaryRef.
+void* IOBSDNameMatching();
+void rdar33832412() {
+ void* x = IOBSDNameMatching(); // no-warning
+}
diff --git a/test/Analysis/simple-stream-checks.c b/test/Analysis/simple-stream-checks.c
index f47e488110..ca1c781575 100644
--- a/test/Analysis/simple-stream-checks.c
+++ b/test/Analysis/simple-stream-checks.c
@@ -65,7 +65,7 @@ void SymbolEscapedThroughFunctionCall() {
}
FILE *GlobalF;
-void SymbolEscapedThroughAssignmentToGloabl() {
+void SymbolEscapedThroughAssignmentToGlobal() {
FILE *F = fopen("myfile.txt", "w");
GlobalF = F;
return; // no warning
diff --git a/test/Analysis/taint-generic.c b/test/Analysis/taint-generic.c
index 8efed66dac..d3ca246b82 100644
--- a/test/Analysis/taint-generic.c
+++ b/test/Analysis/taint-generic.c
@@ -192,20 +192,41 @@ void testStruct() {
void testStructArray() {
struct {
- char buf[16];
- struct {
- int length;
- } st[1];
- } tainted;
+ int length;
+ } tainted[4];
- char buffer[16];
+ char dstbuf[16], srcbuf[16];
int sock;
sock = socket(AF_INET, SOCK_STREAM, 0);
- read(sock, &tainted.buf[0], sizeof(tainted.buf));
- read(sock, &tainted.st[0], sizeof(tainted.st));
- // FIXME: tainted.st[0].length should be marked tainted
- __builtin_memcpy(buffer, tainted.buf, tainted.st[0].length); // no-warning
+ __builtin_memset(srcbuf, 0, sizeof(srcbuf));
+
+ read(sock, &tainted[0], sizeof(tainted));
+ __builtin_memcpy(dstbuf, srcbuf, tainted[0].length); // expected-warning {{Untrusted data is used to specify the buffer size}}
+
+ __builtin_memset(&tainted, 0, sizeof(tainted));
+ read(sock, &tainted, sizeof(tainted));
+ __builtin_memcpy(dstbuf, srcbuf, tainted[0].length); // expected-warning {{Untrusted data is used to specify the buffer size}}
+
+ __builtin_memset(&tainted, 0, sizeof(tainted));
+ // If we taint element 1, we should not raise an alert on taint for element 0 or element 2
+ read(sock, &tainted[1], sizeof(tainted));
+ __builtin_memcpy(dstbuf, srcbuf, tainted[0].length); // no-warning
+ __builtin_memcpy(dstbuf, srcbuf, tainted[2].length); // no-warning
+}
+
+void testUnion() {
+ union {
+ int x;
+ char y[4];
+ } tainted;
+
+ char buffer[4];
+
+ int sock = socket(AF_INET, SOCK_STREAM, 0);
+ read(sock, &tainted.y, sizeof(tainted.y));
+ // FIXME: overlapping regions aren't detected by isTainted yet
+ __builtin_memcpy(buffer, tainted.y, tainted.x);
}
int testDivByZero() {
diff --git a/test/Analysis/temp-obj-dtors-cfg-output.cpp b/test/Analysis/temp-obj-dtors-cfg-output.cpp
index 372443bedf..05b6a31059 100644
--- a/test/Analysis/temp-obj-dtors-cfg-output.cpp
+++ b/test/Analysis/temp-obj-dtors-cfg-output.cpp
@@ -834,7 +834,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
-// CHECK: 1: [B7.2] ?: [B6.6]
+// CXX98: 1: [B7.2] ?: [B6.6]
+// CXX11: 1: [B7.3] ?: [B6.6]
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
// CHECK: 4: [B4.3] (CXXConstructExpr, class A)
@@ -843,10 +844,13 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (2): B5 B6
// CHECK: Succs (2): B3 B2
// CHECK: [B5]
-// CHECK: 1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 2: [B5.1]
-// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
-// CHECK: 4: [B5.3] (BindTemporary)
+// CXX98: 1: [B7.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98: 2: [B5.1]
+// CXX98: 3: [B5.2] (CXXConstructExpr, class A)
+// CXX98: 4: [B5.3] (BindTemporary)
+// CXX11: 1: [B7.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11: 2: [B5.1] (CXXConstructExpr, class A)
+// CXX11: 3: [B5.2] (BindTemporary)
// CHECK: Preds (1): B7
// CHECK: Succs (1): B4
// CHECK: [B6]
@@ -861,10 +865,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B7]
// CHECK: 1: A() (CXXConstructExpr, class A)
// CHECK: 2: [B7.1] (BindTemporary)
-// CHECK: 3: [B7.2].operator bool
-// CHECK: 4: [B7.2]
-// CHECK: 5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B7.5] ? ... : ...
+// CXX98: 3: [B7.2].operator bool
+// CXX98: 4: [B7.2]
+// CXX98: 5: [B7.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98: T: [B7.5] ? ... : ...
+// CXX11: 3: [B7.2]
+// CXX11: 4: [B7.3].operator bool
+// CXX11: 5: [B7.3]
+// CXX11: 6: [B7.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11: T: [B7.6] ? ... : ...
// CHECK: Preds (1): B8
// CHECK: Succs (2): B5 B6
// CHECK: [B0 (EXIT)]
@@ -886,7 +895,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B4
// CHECK: Succs (1): B1
// CHECK: [B4]
-// CHECK: 1: [B7.4] ?: [B6.6]
+// CXX98: 1: [B7.4] ?: [B6.6]
+// CXX11: 1: [B7.5] ?: [B6.6]
// CHECK: 2: [B4.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B4.2]
// CHECK: 4: [B7.2]([B4.3])
@@ -894,10 +904,13 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (2): B5 B6
// CHECK: Succs (2): B3 B2
// CHECK: [B5]
-// CHECK: 1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 2: [B5.1]
-// CHECK: 3: [B5.2] (CXXConstructExpr, class A)
-// CHECK: 4: [B5.3] (BindTemporary)
+// CXX98: 1: [B7.4] (ImplicitCastExpr, NoOp, const class A)
+// CXX98: 2: [B5.1]
+// CXX98: 3: [B5.2] (CXXConstructExpr, class A)
+// CXX98: 4: [B5.3] (BindTemporary)
+// CXX11: 1: [B7.5] (ImplicitCastExpr, NoOp, const class A)
+// CXX11: 2: [B5.1] (CXXConstructExpr, class A)
+// CXX11: 3: [B5.2] (BindTemporary)
// CHECK: Preds (1): B7
// CHECK: Succs (1): B4
// CHECK: [B6]
@@ -914,10 +927,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: 2: [B7.1] (ImplicitCastExpr, FunctionToPointerDecay, void (*)(const class A &))
// CHECK: 3: A() (CXXConstructExpr, class A)
// CHECK: 4: [B7.3] (BindTemporary)
-// CHECK: 5: [B7.4].operator bool
-// CHECK: 6: [B7.4]
-// CHECK: 7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B7.7] ? ... : ...
+// CXX98: 5: [B7.4].operator bool
+// CXX98: 6: [B7.4]
+// CXX98: 7: [B7.6] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98: T: [B7.7] ? ... : ...
+// CXX11: 5: [B7.4]
+// CXX11: 6: [B7.5].operator bool
+// CXX11: 7: [B7.5]
+// CXX11: 8: [B7.7] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11: T: [B7.8] ? ... : ...
// CHECK: Preds (2): B8 B9
// CHECK: Succs (2): B5 B6
// CHECK: [B8]
@@ -925,7 +943,8 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (1): B9
// CHECK: Succs (1): B7
// CHECK: [B9]
-// CHECK: 1: [B12.2] ?: [B11.6]
+// CXX98: 1: [B12.2] ?: [B11.6]
+// CXX11: 1: [B12.3] ?: [B11.6]
// CHECK: 2: [B9.1] (ImplicitCastExpr, NoOp, const class A)
// CHECK: 3: [B9.2]
// CHECK: 4: const A &a = A() ?: A();
@@ -933,10 +952,13 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: Preds (2): B10 B11
// CHECK: Succs (2): B8 B7
// CHECK: [B10]
-// CHECK: 1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
-// CHECK: 2: [B10.1]
-// CHECK: 3: [B10.2] (CXXConstructExpr, class A)
-// CHECK: 4: [B10.3] (BindTemporary)
+// CXX98: 1: [B12.2] (ImplicitCastExpr, NoOp, const class A)
+// CXX98: 2: [B10.1]
+// CXX98: 3: [B10.2] (CXXConstructExpr, class A)
+// CXX98: 4: [B10.3] (BindTemporary)
+// CXX11: 1: [B12.3] (ImplicitCastExpr, NoOp, const class A)
+// CXX11: 2: [B10.1] (CXXConstructExpr, class A)
+// CXX11: 3: [B10.2] (BindTemporary)
// CHECK: Preds (1): B12
// CHECK: Succs (1): B9
// CHECK: [B11]
@@ -951,10 +973,15 @@ int testConsistencyNestedNormalReturn(bool value) {
// CHECK: [B12]
// CHECK: 1: A() (CXXConstructExpr, class A)
// CHECK: 2: [B12.1] (BindTemporary)
-// CHECK: 3: [B12.2].operator bool
-// CHECK: 4: [B12.2]
-// CHECK: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
-// CHECK: T: [B12.5] ? ... : ...
+// CXX98: 3: [B12.2].operator bool
+// CXX98: 4: [B12.2]
+// CXX98: 5: [B12.4] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX98: T: [B12.5] ? ... : ...
+// CXX11: 3: [B12.2]
+// CXX11: 4: [B12.3].operator bool
+// CXX11: 5: [B12.3]
+// CXX11: 6: [B12.5] (ImplicitCastExpr, UserDefinedConversion, _Bool)
+// CXX11: T: [B12.6] ? ... : ...
// CHECK: Preds (1): B13
// CHECK: Succs (2): B10 B11
// CHECK: [B0 (EXIT)]
diff --git a/test/Analysis/temporaries-callback-order.cpp b/test/Analysis/temporaries-callback-order.cpp
new file mode 100644
index 0000000000..df916cc4e7
--- /dev/null
+++ b/test/Analysis/temporaries-callback-order.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=debug.AnalysisOrder -analyzer-config debug.AnalysisOrder:Bind=true -analyzer-config debug.AnalysisOrder:RegionChanges=true %s 2>&1 | FileCheck %s
+
+struct Super {
+ virtual void m();
+};
+struct Sub : Super {
+ virtual void m() {}
+};
+
+void testTemporaries() {
+ // This triggers RegionChanges twice:
+ // - Once for zero-initialization of the structure.
+ // - Once for creating a temporary region and copying the structure there.
+ // FIXME: This code shouldn't really produce the extra temporary, however
+ // that's how we behave for now.
+ Sub().m();
+}
+
+void seeIfCheckBindWorks() {
+ // This should trigger checkBind. The rest of the code shouldn't.
+ // This also triggers checkRegionChanges after that.
+ // Note that this function is analyzed first, so the messages would be on top.
+ int x = 1;
+}
+
+// seeIfCheckBindWorks():
+// CHECK: Bind
+// CHECK-NEXT: RegionChanges
+
+// testTemporaries():
+// CHECK-NEXT: RegionChanges
+// CHECK-NEXT: RegionChanges
+
+// Make sure there's no further output.
+// CHECK-NOT: Bind
+// CHECK-NOT: RegionChanges
diff --git a/test/Analysis/temporaries.cpp b/test/Analysis/temporaries.cpp
index 2c052f8b51..99851dd685 100644
--- a/test/Analysis/temporaries.cpp
+++ b/test/Analysis/temporaries.cpp
@@ -503,3 +503,30 @@ namespace PR32088 {
});
}
}
+
+namespace CopyToTemporaryCorrectly {
+class Super {
+public:
+ void m() {
+ mImpl();
+ }
+ virtual void mImpl() = 0;
+};
+class Sub : public Super {
+public:
+ Sub(const int &p) : j(p) {}
+ virtual void mImpl() override {
+ // Used to be undefined pointer dereference because we didn't copy
+ // the subclass data (j) to the temporary object properly.
+ (void)(j + 1); // no-warning
+ if (j != 22) {
+ clang_analyzer_warnIfReached(); // no-warning
+ }
+ }
+ const int &j;
+};
+void run() {
+ int i = 22;
+ Sub(i).m();
+}
+}
diff --git a/test/Analysis/uninit-const.cpp b/test/Analysis/uninit-const.cpp
index 75e932a77c..db969bfb67 100644
--- a/test/Analysis/uninit-const.cpp
+++ b/test/Analysis/uninit-const.cpp
@@ -122,7 +122,7 @@ void f1(void) {
}
void f_uninit(void) {
- int x;
+ int x; // expected-note {{'x' declared without an initial value}}
doStuff_uninit(&x); // expected-warning {{1st function call argument is a pointer to uninitialized value}}
// expected-note@-1 {{1st function call argument is a pointer to uninitialized value}}
}
diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c
index 3eccd51d2c..481f545e28 100644
--- a/test/Analysis/unix-fns.c
+++ b/test/Analysis/unix-fns.c
@@ -1,7 +1,7 @@
-// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,unix.API,osx.API %s -analyzer-store=region -analyzer-output=plist -analyzer-eagerly-assume -analyzer-config faux-bodies=true -analyzer-config path-diagnostics-alternate=false -fblocks -verify -o %t.plist
+// RUN: %clang_analyze_cc1 -triple x86_64-apple-darwin10 -analyzer-checker=core,unix.API,osx.API,optin.portability %s -analyzer-store=region -analyzer-output=plist -analyzer-eagerly-assume -analyzer-config faux-bodies=true -analyzer-config path-diagnostics-alternate=false -fblocks -verify -o %t.plist
// RUN: FileCheck --input-file=%t.plist %s
// RUN: mkdir -p %t.dir
-// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API,osx.API -analyzer-output=html -analyzer-config faux-bodies=true -fblocks -o %t.dir %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,unix.API,osx.API,optin.portability -analyzer-output=html -analyzer-config faux-bodies=true -fblocks -o %t.dir %s
// RUN: rm -fR %t.dir
struct _opaque_pthread_once_t {
long __sig;
diff --git a/test/Analysis/unreachable-code-path.c b/test/Analysis/unreachable-code-path.c
index ff58587be2..effa4d9bfa 100644
--- a/test/Analysis/unreachable-code-path.c
+++ b/test/Analysis/unreachable-code-path.c
@@ -213,3 +213,13 @@ void macro(void) {
RETURN(1); // no-warning
}
+// Avoid FP when macro argument is known
+void writeSomething(int *x);
+#define MACRO(C) \
+ if (!C) { \
+ static int x; \
+ writeSomething(&x); \
+ }
+void macro2(void) {
+ MACRO(1);
+}
diff --git a/test/Analysis/unsupported-types.c b/test/Analysis/unsupported-types.c
new file mode 100644
index 0000000000..9233095e42
--- /dev/null
+++ b/test/Analysis/unsupported-types.c
@@ -0,0 +1,31 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -triple x86_64-unknown-linux -verify %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=core,debug.ExprInspection -triple powerpc64-linux-gnu -verify %s
+
+#define _Complex_I (__extension__ 1.0iF)
+
+void clang_analyzer_eval(int);
+
+void complex_float(double _Complex x, double _Complex y) {
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ if (x != 1.0 + 3.0 * _Complex_I && y != 1.0 - 4.0 * _Complex_I)
+ return
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x + y == 2.0 - 1.0 * _Complex_I); // expected-warning{{UNKNOWN}}
+}
+
+void complex_int(int _Complex x, int _Complex y) {
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ if (x != 1.0 + 3.0 * _Complex_I && y != 1.0 - 4.0 * _Complex_I)
+ return
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x + y == 2.0 - 1.0 * _Complex_I); // expected-warning{{UNKNOWN}}
+}
+
+void longdouble_float(long double x, long double y) {
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ if (x != 0.0L && y != 1.0L)
+ return
+ clang_analyzer_eval(x == y); // expected-warning{{UNKNOWN}}
+ clang_analyzer_eval(x + y == 1.0L); // expected-warning{{UNKNOWN}}
+}
diff --git a/test/Analysis/virtualcall.cpp b/test/Analysis/virtualcall.cpp
index 56bd32446e..c22a8463c0 100644
--- a/test/Analysis/virtualcall.cpp
+++ b/test/Analysis/virtualcall.cpp
@@ -1,98 +1,83 @@
-// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -verify -std=c++11 %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:Interprocedural=true -DINTERPROCEDURAL=1 -verify -std=c++11 %s
-// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -verify -std=c++11 %s
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-output=text -verify -std=c++11 %s
-/* When INTERPROCEDURAL is set, we expect diagnostics in all functions reachable
- from a constructor or destructor. If it is not set, we expect diagnostics
- only in the constructor or destructor.
+// RUN: %clang_analyze_cc1 -analyzer-checker=optin.cplusplus.VirtualCall -analyzer-store region -analyzer-config optin.cplusplus.VirtualCall:PureOnly=true -DPUREONLY=1 -analyzer-output=text -verify -std=c++11 %s
- When PUREONLY is set, we expect diagnostics only for calls to pure virtual
- functions not to non-pure virtual functions.
-*/
+#include "virtualcall.h"
class A {
public:
A();
- A(int i);
- ~A() {};
-
- virtual int foo() = 0; // from Sema: expected-note {{'foo' declared here}}
+ ~A(){};
+
+ virtual int foo() = 0;
virtual void bar() = 0;
void f() {
foo();
-#if INTERPROCEDURAL
- // expected-warning-re@-2 {{{{^}}Call Path : foo <-- fCall to pure virtual function during construction has undefined behavior}}
-#endif
+ // expected-warning-re@-1 {{{{^}}Call to pure virtual function during construction}}
+ // expected-note-re@-2 {{{{^}}Call to pure virtual function during construction}}
}
};
class B : public A {
public:
- B() {
- foo();
+ B() { // expected-note {{Calling default constructor for 'A'}}
+ foo();
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
-#endif
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'B' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
-
}
~B();
-
+
virtual int foo();
- virtual void bar() { foo(); }
-#if INTERPROCEDURAL
- // expected-warning-re@-2 {{{{^}}Call Path : foo <-- barCall to virtual function during destruction will not dispatch to derived class}}
+ virtual void bar() {
+ foo();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during destruction}}
+ // expected-note-re@-3 {{{{^}}Call to virtual function during destruction}}
#endif
+ }
};
-A::A() {
- f();
-}
-
-A::A(int i) {
- foo(); // From Sema: expected-warning {{call to pure virtual member function 'foo' has undefined behavior}}
-#if INTERPROCEDURAL
- // expected-warning-re@-2 {{{{^}}Call Path : fooCall to pure virtual function during construction has undefined behavior}}
-#else
- // expected-warning-re@-4 {{{{^}}Call to pure virtual function during construction has undefined behavior}}
-#endif
+A::A() {
+ f();
+// expected-note-re@-1 {{{{^}}This constructor of an object of type 'A' has not returned when the virtual method was called}}
+// expected-note-re@-2 {{{{^}}Calling 'A::f'}}
}
B::~B() {
this->B::foo(); // no-warning
this->B::bar();
- this->foo();
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during destruction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during destruction will not dispatch to derived class}}
+ // expected-note-re@-2 {{{{^}}This destructor of an object of type '~B' has not returned when the virtual method was called}}
+ // expected-note-re@-3 {{{{^}}Calling 'B::bar'}}
#endif
+ this->foo();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during destruction}}
+ // expected-note-re@-3 {{{{^}}This destructor of an object of type '~B' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during destruction}}
#endif
-
+
}
class C : public B {
public:
C();
~C();
-
+
virtual int foo();
void f(int i);
};
C::C() {
- f(foo());
+ f(foo());
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
-#endif
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'C' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
}
@@ -112,30 +97,198 @@ public:
foo(); // no-warning
}
~E() { bar(); }
+#if !PUREONLY
+ // expected-note-re@-2 2{{{{^}}Calling '~B'}}
+#endif
int foo() override;
};
-// Regression test: don't crash when there's no direct callee.
class F {
public:
F() {
- void (F::* ptr)() = &F::foo;
+ void (F::*ptr)() = &F::foo;
(this->*ptr)();
}
void foo();
};
+class G {
+public:
+ G() {}
+ virtual void bar();
+ void foo() {
+ bar(); // no warning
+ }
+};
+
+class H {
+public:
+ H() : initState(0) { init(); }
+ int initState;
+ virtual void f() const;
+ void init() {
+ if (initState)
+ f(); // no warning
+ }
+
+ H(int i) {
+ G g;
+ g.foo();
+ g.bar(); // no warning
+ f();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'H' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ H &h = *this;
+ h.f();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'H' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+};
+
+class X {
+public:
+ X() {
+ g();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'X' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+ X(int i) {
+ if (i > 0) {
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}Taking true branch}}
+ // expected-note-re@-3 {{{{^}}Taking false branch}}
+#endif
+ X x(i - 1);
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}Calling constructor for 'X'}}
+#endif
+ x.g(); // no warning
+ }
+ g();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'X' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+ virtual void g();
+};
+
+class M;
+class N {
+public:
+ virtual void virtualMethod();
+ void callFooOfM(M *);
+};
+class M {
+public:
+ M() {
+ N n;
+ n.virtualMethod(); // no warning
+ n.callFooOfM(this);
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}This constructor of an object of type 'M' has not returned when the virtual method was called}}
+ // expected-note-re@-3 {{{{^}}Calling 'N::callFooOfM'}}
+#endif
+ }
+ virtual void foo();
+};
+void N::callFooOfM(M *m) {
+ m->foo();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}Call to virtual function during construction}}
+#endif
+}
+
+class Y {
+public:
+ virtual void foobar();
+ void fooY() {
+ F f1;
+ foobar();
+#if !PUREONLY
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}Call to virtual function during construction}}
+#endif
+ }
+ Y() { fooY(); }
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}This constructor of an object of type 'Y' has not returned when the virtual method was called}}
+ // expected-note-re@-3 {{{{^}}Calling 'Y::fooY'}}
+#endif
+};
+
int main() {
- A *a;
- B *b;
- C *c;
- D *d;
- E *e;
- F *f;
+ B b;
+#if PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'B'}}
+#else
+ //expected-note-re@-4 2{{{{^}}Calling default constructor for 'B'}}
+#endif
+ C c;
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'C'}}
+#endif
+ D d;
+ E e;
+ F f;
+ G g;
+ H h;
+ H h1(1);
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling constructor for 'H'}}
+ //expected-note-re@-3 {{{{^}}Calling constructor for 'H'}}
+#endif
+ X x;
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'X'}}
+#endif
+ X x1(1);
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling constructor for 'X'}}
+#endif
+ M m;
+#if !PUREONLY
+ //expected-note-re@-2 {{{{^}}Calling default constructor for 'M'}}
+#endif
+ Y *y = new Y;
+ delete y;
+ header::Z z;
+#if !PUREONLY
+ // expected-note-re@-2 {{{{^}}Calling default constructor for 'Z'}}
+#endif
}
+#if !PUREONLY
+ //expected-note-re@-2 2{{{{^}}Calling '~E'}}
+#endif
-#include "virtualcall.h"
+namespace PR34451 {
+struct a {
+ void b() {
+ a c[1];
+ c->b();
+ }
+};
-#define AS_SYSTEM
-#include "virtualcall.h"
-#undef AS_SYSTEM
+class e {
+ public:
+ void b() const;
+};
+
+class c {
+ void m_fn2() const;
+ e d[];
+};
+
+void c::m_fn2() const { d->b(); }
+}
diff --git a/test/Analysis/virtualcall.h b/test/Analysis/virtualcall.h
index c2ad8a6444..e2fde2415e 100644
--- a/test/Analysis/virtualcall.h
+++ b/test/Analysis/virtualcall.h
@@ -1,36 +1,14 @@
-#ifdef AS_SYSTEM
-#pragma clang system_header
-
-namespace system {
- class A {
- public:
- A() {
- foo(); // no-warning
- }
-
- virtual int foo();
- };
-}
-
-#else
-
namespace header {
- class A {
+ class Z {
public:
- A() {
+ Z() {
foo();
#if !PUREONLY
-#if INTERPROCEDURAL
- // expected-warning-re@-3 {{{{^}}Call Path : fooCall to virtual function during construction will not dispatch to derived class}}
-#else
- // expected-warning-re@-5 {{{{^}}Call to virtual function during construction will not dispatch to derived class}}
-#endif
+ // expected-warning-re@-2 {{{{^}}Call to virtual function during construction}}
+ // expected-note-re@-3 {{{{^}}This constructor of an object of type 'Z' has not returned when the virtual method was called}}
+ // expected-note-re@-4 {{{{^}}Call to virtual function during construction}}
#endif
-
}
-
virtual int foo();
};
}
-
-#endif