Files
clang-p2996/clang/test/Analysis/inlining/containers.cpp
Jordan Rose 7023a90378 [analyzer] Don't inline the [cd]tors of C++ iterators.
This goes with r178516, which instructed the analyzer not to inline the
constructors and destructors of C++ container classes. This goes a step
further and does the same thing for iterators, so that the analyzer won't
falsely decide we're trying to construct an iterator pointing to a
nonexistent element.

The heuristic for determining whether something is an iterator is the
presence of an 'iterator_category' member. This is controlled under the
same -analyzer-config option as container constructor/destructor inlining:
'c++-container-inlining'.

<rdar://problem/13770187>

llvm-svn: 180890
2013-05-01 22:39:31 +00:00

242 lines
5.0 KiB
C++

// 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 // HEADER
#include "../Inputs/system-header-simulator-cxx.h"
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;
typedef std::forward_iterator_tag iterator_category;
IterImpl(MySet::iterator i) : impl(i) {
clang_analyzer_checkInlined(true);
#if INLINE
// expected-warning@-2 {{TRUE}}
#endif
}
};
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 // HEADER