diff options
author | Jordan Rose <jordan_rose@apple.com> | 2013-04-02 00:26:35 +0000 |
---|---|---|
committer | Jordan Rose <jordan_rose@apple.com> | 2013-04-02 00:26:35 +0000 |
commit | c63a460d78a7625ff38d2b3580f78030c44f07db (patch) | |
tree | 92f8f273c29d583cb32ed3fabc63c67cd5473937 /test/Analysis/inlining/containers.cpp | |
parent | c9092bb5eb67d859122abb69a0ef61e9249500cd (diff) |
[analyzer] For now, don't inline [cd]tors of C++ containers.
This is a heuristic to make up for the fact that the analyzer doesn't
model C++ containers very well. One example is modeling that
'std::distance(I, E) == 0' implies 'I == E'. In the future, it would be
nice to model this explicitly, but for now it just results in a lot of
false positives.
The actual heuristic checks if the base type has a member named 'begin' or
'iterator'. If so, we treat the constructors and destructors of that type
as opaque, rather than inlining them.
This is intended to drastically reduce the number of false positives
reported with experimental destructor support turned on. We can tweak the
heuristic in the future, but we'd rather err on the side of false negatives
for now.
<rdar://problem/13497258>
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@178516 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Analysis/inlining/containers.cpp')
-rw-r--r-- | test/Analysis/inlining/containers.cpp | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/test/Analysis/inlining/containers.cpp b/test/Analysis/inlining/containers.cpp new file mode 100644 index 0000000000..4500dff6dc --- /dev/null +++ b/test/Analysis/inlining/containers.cpp @@ -0,0 +1,234 @@ +// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=false -verify %s +// RUN: %clang_cc1 -analyze -std=c++11 -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-config c++-inlining=destructors -analyzer-config c++-container-inlining=true -DINLINE=1 -verify %s + +#ifndef HEADER + +void clang_analyzer_eval(bool); +void clang_analyzer_checkInlined(bool); + +#define HEADER +#include "containers.cpp" +#undef HEADER + +void test() { + MySet set(0); + + clang_analyzer_eval(set.isEmpty()); +#if INLINE + // expected-warning@-2 {{TRUE}} +#else + // expected-warning@-4 {{UNKNOWN}} +#endif + + clang_analyzer_eval(set.raw_begin() == set.raw_end()); +#if INLINE + // expected-warning@-2 {{TRUE}} +#else + // expected-warning@-4 {{UNKNOWN}} +#endif + + clang_analyzer_eval(set.begin().impl == set.end().impl); +#if INLINE + // expected-warning@-2 {{TRUE}} +#else + // expected-warning@-4 {{UNKNOWN}} +#endif +} + +void testSubclass(MySetSubclass &sub) { + sub.useIterator(sub.begin()); + + MySetSubclass local; +} + +void testWrappers(BeginOnlySet &w1, IteratorStructOnlySet &w2, + IteratorTypedefOnlySet &w3, IteratorUsingOnlySet &w4) { + BeginOnlySet local1; + IteratorStructOnlySet local2; + IteratorTypedefOnlySet local3; + IteratorUsingOnlySet local4; + + clang_analyzer_eval(w1.begin().impl.impl == w1.begin().impl.impl); +#if INLINE + // expected-warning@-2 {{TRUE}} +#else + // expected-warning@-4 {{UNKNOWN}} +#endif + + clang_analyzer_eval(w2.start().impl == w2.start().impl); +#if INLINE + // expected-warning@-2 {{TRUE}} +#else + // expected-warning@-4 {{UNKNOWN}} +#endif + + clang_analyzer_eval(w3.start().impl == w3.start().impl); +#if INLINE + // expected-warning@-2 {{TRUE}} +#else + // expected-warning@-4 {{UNKNOWN}} +#endif + + clang_analyzer_eval(w4.start().impl == w4.start().impl); +#if INLINE + // expected-warning@-2 {{TRUE}} +#else + // expected-warning@-4 {{UNKNOWN}} +#endif +} + + +#else + +class MySet { + int *storage; + unsigned size; +public: + MySet() : storage(0), size(0) { + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif + } + + MySet(unsigned n) : storage(new int[n]), size(n) { + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif + } + + ~MySet() { delete[] storage; } + + bool isEmpty() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return size == 0; + } + + struct iterator { + int *impl; + + iterator(int *p) : impl(p) {} + }; + + iterator begin() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return iterator(storage); + } + + iterator end() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return iterator(storage+size); + } + + typedef int *raw_iterator; + + raw_iterator raw_begin() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return storage; + } + raw_iterator raw_end() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return storage + size; + } +}; + +class MySetSubclass : public MySet { +public: + MySetSubclass() { + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif + } + + void useIterator(iterator i) { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + } +}; + +class BeginOnlySet { + MySet impl; +public: + struct IterImpl { + MySet::iterator impl; + IterImpl(MySet::iterator i) : impl(i) { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + } + }; + + BeginOnlySet() { + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif + } + + typedef IterImpl wrapped_iterator; + + wrapped_iterator begin() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return IterImpl(impl.begin()); + } +}; + +class IteratorTypedefOnlySet { + MySet impl; +public: + + IteratorTypedefOnlySet() { + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif + } + + typedef MySet::iterator iterator; + + iterator start() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return impl.begin(); + } +}; + +class IteratorUsingOnlySet { + MySet impl; +public: + + IteratorUsingOnlySet() { + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif + } + + using iterator = MySet::iterator; + + iterator start() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return impl.begin(); + } +}; + +class IteratorStructOnlySet { + MySet impl; +public: + + IteratorStructOnlySet() { + clang_analyzer_checkInlined(true); +#if INLINE + // expected-warning@-2 {{TRUE}} +#endif + } + + struct iterator { + int *impl; + }; + + iterator start() { + clang_analyzer_checkInlined(true); // expected-warning {{TRUE}} + return iterator{impl.begin().impl}; + } +}; + +#endif |