summaryrefslogtreecommitdiffstats
path: root/www/analyzer
diff options
context:
space:
mode:
authorAnton Yartsev <anton.yartsev@gmail.com>2014-05-19 15:04:55 +0000
committerAnton Yartsev <anton.yartsev@gmail.com>2014-05-19 15:04:55 +0000
commit76790c5cf0edc160c8dadc31ff8d6d439dc8ece1 (patch)
treec25f7904566124d84d09ef74c1d60b91e36adc5d /www/analyzer
parent323f398054bf96fb5ba3fc7c347ca615581cd037 (diff)
[analyzer] Alpha and implicit checker lists, expand/collapse feature.
The list of alpha and the list of implicit checkers added. An ability to expand/collapse long texts added. Markup fixed. http://reviews.llvm.org/D3457 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@209131 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'www/analyzer')
-rw-r--r--www/analyzer/alpha_checks.html848
-rw-r--r--www/analyzer/available_checks.html38
-rw-r--r--www/analyzer/checker_dev_manual.html6
-rw-r--r--www/analyzer/content.css5
-rw-r--r--www/analyzer/images/expandcollapse/arrows_dark.gifbin0 -> 1377 bytes
-rw-r--r--www/analyzer/images/expandcollapse/arrows_light.gifbin0 -> 1376 bytes
-rw-r--r--www/analyzer/images/expandcollapse/ellipses_dark.gifbin0 -> 1360 bytes
-rw-r--r--www/analyzer/images/expandcollapse/ellipses_light.gifbin0 -> 1359 bytes
-rw-r--r--www/analyzer/implicit_checks.html165
-rw-r--r--www/analyzer/potential_checkers.html108
-rw-r--r--www/analyzer/scripts/expandcollapse.js191
11 files changed, 1271 insertions, 90 deletions
diff --git a/www/analyzer/alpha_checks.html b/www/analyzer/alpha_checks.html
new file mode 100644
index 0000000000..6f5e4f1708
--- /dev/null
+++ b/www/analyzer/alpha_checks.html
@@ -0,0 +1,848 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Alpha Checks</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <script type="text/javascript" src="scripts/menu.js"></script>
+ <script type="text/javascript" src="scripts/expandcollapse.js"></script>
+ <style type="text/css">
+ tr:first-child { width:20%; }
+ </style>
+</head>
+<body onload="initExpandCollapse()">
+
+<div id="page">
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+<h1>Alpha Checkers</h1>
+Experimental checkers in addition to the <a href = "available_checks.html">
+Default Checkers</a>. These are checkers with known issues or limitations that
+keep them from being on by default. They are likely to have false positives.
+Bug reports are welcome but will likely not be investigated for some time.
+Patches welcome!
+<ul>
+<li><a href="#core_alpha_checkers">Core Alpha Checkers</a></li>
+<li><a href="#cplusplus_alpha_checkers">C++ Alpha Checkers</a></li>
+<li><a href="#deadcode_alpha_checkers">Dead Code Alpha Checkers</a></li>
+<li><a href="#osx_alpha_checkers">OS X Alpha Checkers</a></li>
+<li><a href="#security_alpha_checkers">Security Alpha Checkers</a></li>
+<li><a href="#unix_alpha_checkers">Unix Alpha Checkers</a></li>
+</ul>
+
+<!------------------------------ core alpha ----------------------------------->
+<h3 id="core_alpha_checkers">Core Alpha Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.BoolAssignment</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warn about assigning non-{0,1} values to boolean variables.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ BOOL b = -1; // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.CastSize</span><span class="lang">
+(C)</span><div class="descr">
+Check when casting a malloc'ed type T, whether the size is a multiple of the
+size of T (Works only with <span class="name">unix.Malloc</span>
+or <span class="name">alpha.unix.MallocWithAnnotations</span>
+checks enabled).</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int *x = (int *)malloc(11); // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.CastToStruct</span><span class="lang">
+(C, C++)</span><div class="descr">
+Check for cast from non-struct pointer to struct pointer.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+// C
+struct s {};
+
+void test(int *p) {
+ struct s *ps = (struct s *) p; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// C++
+class c {};
+
+void test(int *p) {
+ c *pc = (c *) p; // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.FixedAddr</span><span class="lang">
+(C)</span><div class="descr">
+Check for assignment of a fixed address to a pointer.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int *p;
+ p = (int *) 0x10000; // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.IdenticalExpr</span><span class="lang">
+(C, C++)</span><div class="descr">
+Warn about suspicious uses of identical expressions.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+// C
+void test() {
+ int a = 5;
+ int b = a | 4 | a; // warn: identical expr on both sides
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// C++
+bool f(void);
+
+void test(bool b) {
+ int i = 10;
+ if (f()) { // warn: true and false branches are identical
+ do {
+ i--;
+ } while (f());
+ } else {
+ do {
+ i--;
+ } while (f());
+ }
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.PointerArithm</span><span class="lang">
+(C)</span><div class="descr">
+Check for pointer arithmetic on locations other than array
+elements.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int x;
+ int *p;
+ p = &amp;x + 1; // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.PointerSub</span><span class="lang">
+(C)</span><div class="descr">
+Check for pointer subtractions on two pointers pointing to different memory
+chunks.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int x, y;
+ int d = &amp;y - &amp;x; // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.core.SizeofPtr</span><span class="lang">
+(C)</span><div class="descr">
+Warn about unintended use of <code>sizeof()</code> on pointer
+expressions.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+struct s {};
+
+int test(struct s *p) {
+ return sizeof(p);
+ // warn: sizeof(ptr) can produce an unexpected result
+}
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+<!--------------------------- cplusplus alpha --------------------------------->
+<h3 id="cplusplus_alpha_checkers">C++ Alpha Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.cplusplus.NewDeleteLeaks</span><span class="lang">
+(C++)</span><div class="descr">
+Check for memory leaks. Traces memory managed by <code>new</code>/<code>
+delete</code>.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int *p = new int;
+} // warn
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.cplusplus.VirtualCall</span><span class="lang">
+(C++)</span><div class="descr">
+Check virtual member function calls during construction or
+destruction.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+class A {
+public:
+ A() {
+ f(); // warn
+ }
+ virtual void f();
+};
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+class A {
+public:
+ ~A() {
+ this-&gt;f(); // warn
+ }
+ virtual void f();
+};
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+<!--------------------------- dead code alpha --------------------------------->
+<h3 id="deadcode_alpha_checkers">Dead Code Alpha Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.deadcode.UnreachableCode</span><span class="lang">
+(C, C++, ObjC)</span><div class="descr">
+Check unreachable code.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+// C
+int test() {
+ int x = 1;
+ while(x);
+ return x; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// C++
+void test() {
+ int a = 2;
+
+ while (a > 1)
+ a--;
+
+ if (a > 1)
+ a++; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// Objective-C
+void test(id x) {
+ return;
+ [x retain]; // warn
+}
+</pre></div></div></td></tr>
+</tbody></table>
+
+<!---------------------------- OS X alpha -------------------------------------->
+<h3 id="osx_alpha_checkers">OS X Alpha Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.osx.cocoa.Dealloc</span><span class="lang">
+(ObjC)</span><div class="descr">
+Warn about Objective-C classes that lack a correct implementation
+of <code>-dealloc</code>.
+</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+@interface MyObject : NSObject {
+ id _myproperty;
+}
+@end
+
+@implementation MyObject // warn: lacks 'dealloc'
+@end
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+@interface MyObject : NSObject {}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject // warn: does not send 'dealloc' to super
+- (void)dealloc {
+ self.myproperty = 0;
+}
+@end
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+@interface MyObject : NSObject {
+ id _myproperty;
+}
+@property(retain) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty = _myproperty;
+ // warn: var was retained but wasn't released
+- (void)dealloc {
+ [super dealloc];
+}
+@end
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+@interface MyObject : NSObject {
+ id _myproperty;
+}
+@property(assign) id myproperty;
+@end
+
+@implementation MyObject
+@synthesize myproperty = _myproperty;
+ // warn: var wasn't retained but was released
+- (void)dealloc {
+ [_myproperty release];
+ [super dealloc];
+}
+@end
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.osx.cocoa.DirectIvarAssignment</span><span class="lang">
+(ObjC)</span><div class="descr">
+Check that Objective C properties follow the following rule: the property
+should be set with the setter, not though a direct assignment.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+@interface MyClass : NSObject {}
+@property (readonly) id A;
+- (void) foo;
+@end
+
+@implementation MyClass
+- (void) foo {
+ _A = 0; // warn
+}
+@end
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions</span><span class="lang">
+(ObjC)</span><div class="descr">
+Check for direct assignments to instance variables in the methods annotated
+with <code>objc_no_direct_instance_variable_assignment</code>.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+@interface MyClass : NSObject {}
+@property (readonly) id A;
+- (void) fAnnotated __attribute__((
+ annotate("objc_no_direct_instance_variable_assignment")));
+- (void) fNotAnnotated;
+@end
+
+@implementation MyClass
+- (void) fAnnotated {
+ _A = 0; // warn
+}
+- (void) fNotAnnotated {
+ _A = 0; // no warn
+}
+@end
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.osx.cocoa.InstanceVariableInvalidation</span><span class="lang">
+(ObjC)</span><div class="descr">
+Check that the invalidatable instance variables are invalidated in the methods
+annotated with <code>objc_instance_variable_invalidator</code>.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+@protocol Invalidation &lt;NSObject&gt;
+- (void) invalidate
+ __attribute__((annotate("objc_instance_variable_invalidator")));
+@end
+
+@interface InvalidationImpObj : NSObject &lt;Invalidation&gt;
+@end
+
+@interface SubclassInvalidationImpObj : InvalidationImpObj {
+ InvalidationImpObj *var;
+}
+- (void)invalidate;
+@end
+
+@implementation SubclassInvalidationImpObj
+- (void) invalidate {}
+@end
+// warn: var needs to be invalidated or set to nil
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.osx.cocoa.MissingInvalidationMethod</span><span class="lang">
+(ObjC)</span><div class="descr">
+Check that the invalidation methods are present in classes that contain
+invalidatable instance variables.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+@protocol Invalidation &lt;NSObject&gt;
+- (void)invalidate
+ __attribute__((annotate("objc_instance_variable_invalidator")));
+@end
+
+@interface NeedInvalidation : NSObject &lt;Invalidation&gt;
+@end
+
+@interface MissingInvalidationMethodDecl : NSObject {
+ NeedInvalidation *Var; // warn
+}
+@end
+
+@implementation MissingInvalidationMethodDecl
+@end
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+<!------------------------- security alpha ------------------------------------>
+<h3 id="security_alpha_checkers">Security Alpha Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.security.ArrayBound</span><span class="lang">
+(C)</span><div class="descr">
+Warn about buffer overflows (older checker).</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ char *s = "";
+ char c = s[1]; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+struct seven_words {
+ int c[7];
+};
+
+void test() {
+ struct seven_words a, *p;
+ p = &a;
+ p[0] = a;
+ p[1] = a;
+ p[2] = a; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// note: requires unix.Malloc or
+// alpha.unix.MallocWithAnnotations checks enabled.
+void test() {
+ int *p = malloc(12);
+ p[3] = 4; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ char a[2];
+ int *b = (int*)a;
+ b[1] = 3; // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.security.ArrayBoundV2</span><span class="lang">
+(C)</span><div class="descr">
+Warn about buffer overflows (newer checker).</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ char *s = "";
+ char c = s[1]; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ int buf[100];
+ int *p = buf;
+ p = p + 99;
+ p[1] = 1; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// note: compiler has internal check for this.
+// Use -Wno-array-bounds to suppress compiler warning.
+void test() {
+ int buf[100][100];
+ buf[0][-1] = 1; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// note: requires alpha.security.taint check turned on.
+void test() {
+ char s[] = "abc";
+ int x = getchar();
+ char c = s[x]; // warn: index is tainted
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.security.MallocOverflow</span><span class="lang">
+(C)</span><div class="descr">
+Check for overflows in the arguments to <code>malloc()</code>.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test(int n) {
+ void *p = malloc(n * sizeof(int)); // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.security.ReturnPtrRange</span><span class="lang">
+(C)</span><div class="descr">
+Check for an out-of-bound pointer being returned to callers.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+static int A[10];
+
+int *test() {
+ int *p = A + 10;
+ return p; // warn
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+int test(void) {
+ int x;
+ return x; // warn: undefined or garbage returned
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.security.taint.TaintPropagation</span><span class="lang">
+(C)</span><div class="descr">
+Generate taint information used by other checkers.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ char x = getchar(); // 'x' marked as tainted
+ system(&x); // warn: untrusted data is passed to a system call
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// note: compiler internally checks if the second param to
+// sprintf is a string literal or not.
+// Use -Wno-format-security to suppress compiler warning.
+void test() {
+ char s[10], buf[10];
+ fscanf(stdin, "%s", s); // 's' marked as tainted
+
+ sprintf(buf, s); // warn: untrusted data as a format string
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ size_t ts;
+ scanf("%zd", &ts); // 'ts' marked as tainted
+ int *p = (int *)malloc(ts * sizeof(int));
+ // warn: untrusted data as bufer size
+}
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+<!--------------------------- unix alpha -------------------------------------->
+<h3 id="unix_alpha_checkers">Unix Alpha Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.Chroot</span><span class="lang">
+(C)</span><div class="descr">
+Check improper use of <code>chroot</code>.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void f();
+
+void test() {
+ chroot("/usr/local");
+ f(); // warn: no call of chdir("/") immediately after chroot
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.MallocWithAnnotations</span><span class="lang">
+(C)</span><div class="descr">
+Check for memory leaks, double free, and use-after-free problems. Assumes that
+all user-defined functions which might free a pointer are
+annotated.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+
+void test() {
+ int *p = my_malloc(1);
+} // warn: potential leak
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+
+void test() {
+ int *p = my_malloc(1);
+ my_free(p);
+ my_free(p); // warn: attempt to free released
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void __attribute((ownership_returns(malloc))) *my_malloc(size_t);
+void __attribute((ownership_holds(malloc, 1))) my_hold(void *);
+
+void test() {
+ int *p = my_malloc(1);
+ my_hold(p);
+ free(p); // warn: attempt to free non-owned memory
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void __attribute((ownership_takes(malloc, 1))) my_free(void *);
+
+void test() {
+ int *p = malloc(1);
+ my_free(p);
+ *p = 1; // warn: use after free
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.PthreadLock</span><span class="lang">
+(C)</span><div class="descr">
+Simple lock -> unlock checker; applies to:<div class=functions>
+pthread_mutex_lock<br>
+pthread_rwlock_rdlock<br>
+pthread_rwlock_wrlock<br>
+lck_mtx_lock<br>
+lck_rw_lock_exclusive<br>
+lck_rw_lock_shared<br>
+pthread_mutex_trylock<br>
+pthread_rwlock_tryrdlock<br>
+pthread_rwlock_tryrwlock<br>
+lck_mtx_try_lock<br>
+lck_rw_try_lock_exclusive<br>
+lck_rw_try_lock_shared<br>
+pthread_mutex_unlock<br>
+pthread_rwlock_unlock<br>
+lck_mtx_unlock<br>
+lck_rw_done</div></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+pthread_mutex_t mtx;
+
+void test() {
+ pthread_mutex_lock(&mtx);
+ pthread_mutex_lock(&mtx);
+ // warn: this lock has already been acquired
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+lck_mtx_t lck1, lck2;
+
+void test() {
+ lck_mtx_lock(&lck1);
+ lck_mtx_lock(&lck2);
+ lck_mtx_unlock(&lck1);
+ // warn: this was not the most recently acquired lock
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+lck_mtx_t lck1, lck2;
+
+void test() {
+ if (lck_mtx_try_lock(&lck1) == 0)
+ return;
+
+ lck_mtx_lock(&lck2);
+ lck_mtx_unlock(&lck1);
+ // warn: this was not the most recently acquired lock
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.SimpleStream</span><span class="lang">
+(C)</span><div class="descr">
+Check for misuses of stream APIs:<div class=functions>
+fopen<br>
+fclose</div>(demo checker, the subject of the demo
+(<a href="http://llvm.org/devmtg/2012-11/Zaks-Rose-Checker24Hours.pdf">Slides</a>
+,<a href="http://llvm.org/devmtg/2012-11/videos/Zaks-Rose-Checker24Hours.mp4">Video</a>)
+by Anna Zaks and Jordan Rose presented at the <a href="http://llvm.org/devmtg/2012-11/">
+2012 LLVM Developers' Meeting).</a></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ FILE *F = fopen("myfile.txt", "w");
+} // warn: opened file is never closed
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ FILE *F = fopen("myfile.txt", "w");
+
+ if (F)
+ fclose(F);
+
+ fclose(F); // warn: closing a previously closed file stream
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.Stream</span><span class="lang">
+(C)</span><div class="descr">
+Check stream handling functions:<div class=functions>fopen<br>
+tmpfile<br>
+fclose<br>
+fread<br>
+fwrite<br>
+fseek<br>
+ftell<br>
+rewind<br>
+fgetpos<br>
+fsetpos<br>
+clearerr<br>
+feof<br>
+ferror<br>
+fileno</div></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ FILE *p = fopen("foo", "r");
+} // warn: opened file is never closed
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ FILE *p = fopen("foo", "r");
+ fseek(p, 1, SEEK_SET); // warn: stream pointer might be NULL
+ fclose(p);
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ FILE *p = fopen("foo", "r");
+
+ if (p)
+ fseek(p, 1, 3);
+ // warn: third arg should be SEEK_SET, SEEK_END, or SEEK_CUR
+
+ fclose(p);
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ FILE *p = fopen("foo", "r");
+ fclose(p);
+ fclose(p); // warn: already closed
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+void test() {
+ FILE *p = tmpfile();
+ ftell(p); // warn: stream pointer might be NULL
+ fclose(p);
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.cstring.BufferOverlap</span><span class="lang">
+(C)</span><div class="descr">
+Checks for overlap in two buffer arguments; applies to:<div class=functions>
+memcpy<br>
+mempcpy</div></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int a[4] = {0};
+ memcpy(a + 2, a + 1, 8); // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.cstring.NotNullTerminated</span><span class="lang">
+(C)</span><div class="descr">
+Check for arguments which are not null-terminated strings; applies
+to:<div class=functions>
+strlen<br>
+strnlen<br>
+strcpy<br>
+strncpy<br>
+strcat<br>
+strncat</div></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ int y = strlen((char *)&test); // warn
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+alpha.unix.cstring.OutOfBounds</span><span class="lang">
+(C)</span><div class="descr">
+Check for out-of-bounds access in string functions; applies
+to:<div class=functions>
+strncopy<br>
+strncat</div></div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test(char *y) {
+ char x[4];
+ if (strlen(y) == 4)
+ strncpy(x, y, 5); // warn
+}
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+</div> <!-- page -->
+</div> <!-- content -->
+</body>
+</html>
diff --git a/www/analyzer/available_checks.html b/www/analyzer/available_checks.html
index 1f4625ee94..7707fc0150 100644
--- a/www/analyzer/available_checks.html
+++ b/www/analyzer/available_checks.html
@@ -47,15 +47,9 @@ Experimental (Alpha) Checkers</a>.
<h3 id="core_checkers">Core Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
-
-<thead>
-<tr><td><div class="namedescr">Name, Description</div></td>
-<td><div class="example">Example</div></td></tr>
-</thead>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
<tbody>
-
-
<tr><td><div class="namedescr expandable"><span class="name">
core.CallAndMessage</span><span class="lang">
(C, C++, ObjC)</span><div class="descr">
@@ -370,11 +364,7 @@ int test() {
<h3 id="cplusplus_checkers">C++ Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
-
-<thead>
-<tr><td><div class="namedescr">Name, Description</div></td>
-<td><div class="example">Example</div></td></tr>
-</thead>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
<tbody>
<tr><td><div class="namedescr expandable"><span class="name">
@@ -437,11 +427,7 @@ void test() {
<h3 id="deadcode_checkers">Dead Code Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
-
-<thead>
-<tr><td><div class="namedescr">Name, Description</div></td>
-<td><div class="example">Example</div></td></tr>
-</thead>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
<tbody>
<tr><td><div class="namedescr expandable"><span class="name">
@@ -462,11 +448,7 @@ void test() {
<h3 id="osx_checkers">OS X Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
-
-<thead>
-<tr><td><div class="namedescr">Name, Description</div></td>
-<td><div class="example">Example</div></td></tr>
-</thead>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
<tbody>
<tr><td><div class="namedescr expandable"><span class="name">
@@ -877,11 +859,7 @@ void test() {
<h3 id="security_checkers">Security Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
-
-<thead>
-<tr><td><div class="namedescr">Name, Description</div></td>
-<td><div class="example">Example</div></td></tr>
-</thead>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
<tbody>
<tr><td><div class="namedescr expandable"><span class="name">
@@ -1021,11 +999,7 @@ void test() {
<h3 id="unix_checkers">Unix Checkers</h3>
<table class="checkers">
<colgroup><col class="namedescr"><col class="example"></colgroup>
-
-<thead>
-<tr><td><div class="namedescr">Name, Description</div></td>
-<td><div class="example">Example</div></td></tr>
-</thead>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
<tbody>
<tr><td><div class="namedescr expandable"><span class="name">
diff --git a/www/analyzer/checker_dev_manual.html b/www/analyzer/checker_dev_manual.html
index 2216176a13..9c7cd98efa 100644
--- a/www/analyzer/checker_dev_manual.html
+++ b/www/analyzer/checker_dev_manual.html
@@ -47,6 +47,7 @@ for developer guidelines and send your questions and proposals to
<li><a href="#testing">Testing</a></li>
<li><a href="#commands">Useful Commands/Debugging Hints</a></li>
<li><a href="#additioninformation">Additional Sources of Information</a></li>
+ <li><a href="#links">Useful Links</a></li>
</ul>
<h2 id=start>Getting Started</h2>
@@ -605,6 +606,11 @@ href="http://llvm.org/devmtg/2012-11/videos/Zaks-Rose-Checker24Hours.mp4">video<
are available.
</ul>
+<h2 id=links>Useful Links</h2>
+<ul>
+<li>The list of <a href="implicit_checks.html">Implicit Checkers</a></li>
+</ul>
+
</div>
</div>
</body>
diff --git a/www/analyzer/content.css b/www/analyzer/content.css
index 67a9e6d69e..c4d601b4b1 100644
--- a/www/analyzer/content.css
+++ b/www/analyzer/content.css
@@ -84,16 +84,17 @@ table.checkers td.aligned { text-align: center; vertical-align: middle; }
table.checkers col.namedescr { width: 45% }
table.checkers col.example { width: 55% }
table.checkers col.progress { width: 84px }
-table.checkers thead div.example,
+table.checkers thead td,
table.checkers div.namedescr,
table.checkers div.exampleContainer { overflow: hidden; padding: 5px 8px 10px 8px }
/* table.checkers tbody div.example { font-family: monospace; white-space: pre } */
table.checkers div.example { border-top:1px #cccccc dashed; width:100%; padding-top: 5px; margin-top: 5px }
-table.checkers tbody div.example:first-child { border-top:none; padding-top: 0px; margin-top: 0px }
+table.checkers div.example:first-child { border-top:none; padding-top: 0px; margin-top: 0px }
table.checkers span.name { font-weight: bold }
table.checkers span.lang { font-weight: bold; padding-left: 7px; /* display:block; */ }
table.checkers div.descr { margin-top:7px }
table.checkers div.functions { margin-top: 2px; font-style: italic; font-size: 90%; color:#00B }
table.checkers pre { margin: 1px; font-size: 100%; word-wrap: break-word }
table.checkers p { margin: 10px 0px 0px 0px; }
+table.checkers ul, li { margin: 0 }
diff --git a/www/analyzer/images/expandcollapse/arrows_dark.gif b/www/analyzer/images/expandcollapse/arrows_dark.gif
new file mode 100644
index 0000000000..445a3c5533
--- /dev/null
+++ b/www/analyzer/images/expandcollapse/arrows_dark.gif
Binary files differ
diff --git a/www/analyzer/images/expandcollapse/arrows_light.gif b/www/analyzer/images/expandcollapse/arrows_light.gif
new file mode 100644
index 0000000000..4534d05af9
--- /dev/null
+++ b/www/analyzer/images/expandcollapse/arrows_light.gif
Binary files differ
diff --git a/www/analyzer/images/expandcollapse/ellipses_dark.gif b/www/analyzer/images/expandcollapse/ellipses_dark.gif
new file mode 100644
index 0000000000..8ed43b0e7d
--- /dev/null
+++ b/www/analyzer/images/expandcollapse/ellipses_dark.gif
Binary files differ
diff --git a/www/analyzer/images/expandcollapse/ellipses_light.gif b/www/analyzer/images/expandcollapse/ellipses_light.gif
new file mode 100644
index 0000000000..90141ba852
--- /dev/null
+++ b/www/analyzer/images/expandcollapse/ellipses_light.gif
Binary files differ
diff --git a/www/analyzer/implicit_checks.html b/www/analyzer/implicit_checks.html
new file mode 100644
index 0000000000..a476c9bf32
--- /dev/null
+++ b/www/analyzer/implicit_checks.html
@@ -0,0 +1,165 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
+ "http://www.w3.org/TR/html4/strict.dtd">
+<html>
+<head>
+ <title>Implicit Checks</title>
+ <link type="text/css" rel="stylesheet" href="menu.css">
+ <link type="text/css" rel="stylesheet" href="content.css">
+ <script type="text/javascript" src="scripts/menu.js"></script>
+ <script type="text/javascript" src="scripts/expandcollapse.js"></script>
+ <style type="text/css">
+ tr:first-child { width:20%; }
+ </style>
+</head>
+<body onload="initExpandCollapse()">
+
+<div id="page">
+<!--#include virtual="menu.html.incl"-->
+
+<div id="content">
+<h1>Implicit Checkers</h1>
+Even though the implicit checkers do not produce any warnings, they are used to
+support the analyzer core and model known APIs. See also
+<a href = "available_checks.html">Default Checkers</a>
+and <a href = "alpha_checks.html">Experimental (Alpha) Checkers</a>.
+<ul>
+<li><a href="#core_implicit_checkers">Core Implicit Checkers</a></li>
+<li><a href="#osx_implicit_checkers">OS X Implicit Checkers</a></li>
+</ul>
+
+<!------------------------------- core implicit ------------------------------->
+<h3 id="core_implicit_checkers">Core Implicit Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+core.DynamicTypePropagation</span><span class="lang">
+(C++, ObjC)</span><div class="descr">
+Generate dynamic type information.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+// C++
+class A {
+public:
+ A(int x) {}
+ virtual int foo();
+};
+
+class B: public A {
+public:
+ B()
+ :A(foo())
+ // DynamicTypeInfo for 'this' rigion will wrap type 'A'
+ // unless the base constructor call expression is processed
+ {}
+ virtual int foo();
+};
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// Objective-C
+@interface MyClass : NSObject {}
+@end
+
+@implementation MyClass
++ (void)foo {
+ MyClass *x = [[self alloc] init];
+ // DynamicTypeInfo from a cast: from 'id' to 'MyClass *'
+}
+@end
+
+void test() {
+ MyClass *x = [MyClass alloc];
+ // DynamicTypeInfo from a call to alloc:
+ // from 'id' to 'MyClass *'
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+core.builtin.BuiltinFunctions</span><span class="lang">
+(C)</span><div class="descr">
+Evaluate compiler builtin functions (e.g., <code>alloca()</code>)</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test(int x) {
+ int *p = (int *)__builtin_alloca(8);
+ // evaluates to AllocaRegion
+
+ if(__builtin_expect(x > 10, 0)) // evaluates to 'x > 10'
+ x = 0;
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+core.builtin.NoReturnFunctions</span><span class="lang">
+(C, ObjC)</span><div class="descr">
+Evaluate "panic" functions that are known to not return to the caller.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+// C
+void test() {
+ panic(); // generate sink
+}
+</pre></div><div class="separator"></div>
+<div class="example"><pre>
+// Objective-C
+@interface MyObj : NSObject {}
+- (void)foo;
+@end
+
+@implementation MyObj
+- (void)foo {
+ [[NSAssertionHandler currentHandler] handleFailureInMethod:_cmd
+ object:self
+ file:(@"somefile.m")
+ lineNumber:1
+ description:(@"some text")];
+ // generate sink
+}
+@end
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+<!---------------------------- OS X implicit ---------------------------------->
+<h3 id="osx_implicit_checkers">OS X Implicit Checkers</h3>
+<table class="checkers">
+<colgroup><col class="namedescr"><col class="example"></colgroup>
+<thead><tr><td>Name, Description</td><td>Example</td></tr></thead>
+
+<tbody>
+<tr><td><div class="namedescr expandable"><span class="name">
+osx.cocoa.Loops</span><span class="lang">
+(ObjC)</span><div class="descr">
+Improved modeling of loops using Cocoa collection types.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test() {
+ id x;
+ for (x in [NSArray testObject]) {
+ // assume the value of 'x' is non-nil
+ }
+}
+</pre></div></div></td></tr>
+
+
+<tr><td><div class="namedescr expandable"><span class="name">
+osx.cocoa.NonNilReturnValue</span><span class="lang">
+(ObjC)</span><div class="descr">
+Model the APIs that are guaranteed to return a non-nil value.</div></div></td>
+<td><div class="exampleContainer expandable">
+<div class="example"><pre>
+void test(NSArray *A) {
+ id subscriptObj = A[1]; // assume the value is non-nil
+}
+</pre></div></div></td></tr>
+
+</tbody></table>
+
+</div> <!-- page -->
+</div> <!-- content -->
+</body>
+</html>
diff --git a/www/analyzer/potential_checkers.html b/www/analyzer/potential_checkers.html
index a6c568f798..a06e9426fb 100644
--- a/www/analyzer/potential_checkers.html
+++ b/www/analyzer/potential_checkers.html
@@ -5,9 +5,10 @@
<title>List of potential checkers</title>
<link type="text/css" rel="stylesheet" href="content.css">
<link type="text/css" rel="stylesheet" href="menu.css">
+ <script type="text/javascript" src="scripts/expandcollapse.js"></script>
<script type="text/javascript" src="scripts/menu.js"></script>
</head>
-<body>
+<body onload="initExpandCollapse()">
<div id="page">
@@ -470,11 +471,22 @@ int i = *p; // warn
<td class="aligned"></td></tr>
-<!--<tr><td><div class="namedescr expandable"><span class="name">
+<tr><td><div class="namedescr expandable"><span class="name">
undefbehavior.DeadReferenced</span><span class="lang">
(C++)</span><div class="descr">
-Undefined behavior: the following usage of the pointer to the object whose
-lifetime has ended can result in undefined behavior.
+Undefined behavior: the following usage of the pointer to the object whose
+lifetime has ended can result in undefined behavior:<br>
+The object will be or was of a class type with a non-trivial destructor and
+<ul><li>the pointer is used as the operand of a delete-expression</li></ul>
+The object will be or was of a non-POD class type (C++11: any class type) and
+<ul><li>the pointer is used to access a non-static data member or call a
+non-static member function of the object</li>
+<li>the pointer is implicitly converted to a pointer to a base class
+type</li>
+<li>the pointer is used as the operand of a <code>static_cast</code> (except
+when the conversion is to <code>void*</code>, or to <code>void*</code> and
+subsequently to <code>char*</code>, or <code>unsigned char*</code>)</li>
+<li>the pointer is used as the operand of a <code>dynamic_cast</code></li></ul>
<p>Source: C++03 3.8p5, p7; C++11 3.8p5, p7.</p></div></div></td>
<td><div class="exampleContainer expandable">
<div class="example"><pre>
@@ -482,15 +494,15 @@ lifetime has ended can result in undefined behavior.
class A {
public:
- int i;
+ ~A();
};
class B : public A {};
-int test() {
- B *b = new B;
- new(b) A;
- return b-&gt;i; // warn
+void test() {
+ A *a = new A;
+ new(a) B;
+ delete a; // warn
}
</pre></div>
<div class="example"><pre>
@@ -498,90 +510,74 @@ int test() {
class A {
public:
- void f() {};
+ ~A();
};
-class B : public A {};
+class B {};
void test() {
- B *b = new B;
- new(b) A;
- b-&gt;f(); // warn
+ A *a = new A;
+ new(a) B;
+ a->~A();
}
</pre></div>
<div class="example"><pre>
#include &lt;new&gt;
-class A {};
+class A {
+public:
+ ~A();
+};
class B : public A {};
-A* test() {
- B *b = new B;
- new(b) A;
- static_cast&lt;A*&gt;(b); // warn
-}
-</pre></div>
-<div class="example"><pre>
-#include &lt;new&gt;
-
-class A {};
+class C {};
-class B : public A {};
+void f(A*);
-A* test() {
+void test() {
B *b = new B;
- new(b) A;
- dynamic_cast&lt;A*&gt;(b); // warn
+ new(b) C;
+ f(b); // warn
}
</pre></div>
<div class="example"><pre>
#include &lt;new&gt;
-class A {};
+class A {
+public:
+ ~A();
+};
class B : public A {};
+class C {};
+
A* test() {
B *b = new B;
- new(b) A;
- dynamic_cast&lt;A*&gt;(b); // warn
+ new(b) C;
+ return static_cast&lt;A*&gt;(b); // warn
}
</pre></div>
<div class="example"><pre>
#include &lt;new&gt;
-class A {};
-
-class B : public A {};
-
-void test() {
- B *b = new B;
- new(b) A;
- delete b; // warn
-}
-</pre></div>
-<div class="example"><pre>
-// C++11
-#include &lt;new&gt;
-
class A {
public:
- int i;
+ ~A();
};
-class B : public A {
-public:
- ~B() {};
-};
+class B : public A {};
-int test() {
- A *a = new A;
- new(a) B;
- return a-&gt;i; // warn
+class C {};
+
+A* test() {
+ B *b = new B;
+ new(b) C;
+ return dynamic_cast&lt;A*&gt;(b); // warn
}
</pre></div></div></td>
-<td class="aligned"></td></tr>-->
+<td class="aligned"></td></tr>
<tr><td><div class="namedescr expandable"><span class="name">
diff --git a/www/analyzer/scripts/expandcollapse.js b/www/analyzer/scripts/expandcollapse.js
new file mode 100644
index 0000000000..593a9831c8
--- /dev/null
+++ b/www/analyzer/scripts/expandcollapse.js
@@ -0,0 +1,191 @@
+// expand/collapse button (expander) is added if height of a cell content
+// exceeds CLIP_HEIGHT px.
+var CLIP_HEIGHT = 135;
+
+// Height in pixels of an expander image.
+var EXPANDER_HEIGHT = 13;
+
+// Path to images for an expander.
+var imgPath = "./images/expandcollapse/";
+
+// array[group][cell] of { 'height', 'expanded' }.
+// group: a number; cells of the same group belong to the same table row.
+// cell: a number; unique index of a cell in a group.
+// height: a number, px; original height of a cell in a table.
+// expanded: boolean; is a cell expanded or collapsed?
+var CellsInfo = [];
+
+// Extracts group and cell indices from an id of the form identifier_group_cell.
+function getCellIdx(id) {
+ var idx = id.substr(id.indexOf("_") + 1).split("_");
+ return { 'group': idx[0], 'cell': idx[1] };
+}
+
+// Returns { 'height', 'expanded' } info for a cell with a given id.
+function getCellInfo(id) {
+ var idx = getCellIdx(id);
+ return CellsInfo[idx.group][idx.cell];
+}
+
+// Initialization, add nodes, collect info.
+function initExpandCollapse() {
+ if (!document.getElementById)
+ return;
+
+ var groupCount = 0;
+
+ // Examine all table rows in the document.
+ var rows = document.body.getElementsByTagName("tr");
+ for (var i=0; i<rows.length; i+=1) {
+
+ var cellCount=0, newGroupCreated = false;
+
+ // Examine all divs in a table row.
+ var divs = rows[i].getElementsByTagName("div");
+ for (var j=0; j<divs.length; j+=1) {
+
+ var expandableDiv = divs[j];
+
+ if (expandableDiv.className.indexOf("expandable") == -1)
+ continue;
+
+ if (expandableDiv.offsetHeight <= CLIP_HEIGHT)
+ continue;
+
+ // We found a div wrapping a cell content whose height exceeds
+ // CLIP_HEIGHT.
+ var originalHeight = expandableDiv.offsetHeight;
+ // Unique postfix for ids for generated nodes for a given cell.
+ var idxStr = "_" + groupCount + "_" + cellCount;
+ // Create an expander and an additional wrapper for a cell content.
+ //
+ // --- expandableDiv ----
+ // --- expandableDiv --- | ------ data ------ |
+ // | cell content | -> | | cell content | |
+ // --------------------- | ------------------ |
+ // | ---- expander ---- |
+ // ----------------------
+ var data = document.createElement("div");
+ data.className = "data";
+ data.id = "data" + idxStr;
+ data.innerHTML = expandableDiv.innerHTML;
+ with (data.style) { height = (CLIP_HEIGHT - EXPANDER_HEIGHT) + "px";
+ overflow = "hidden" }
+
+ var expander = document.createElement("img");
+ with (expander.style) { display = "block"; paddingTop = "5px"; }
+ expander.src = imgPath + "ellipses_light.gif";
+ expander.id = "expander" + idxStr;
+
+ // Add mouse calbacks to expander.
+ expander.onclick = function() {
+ expandCollapse(this.id);
+ // Hack for Opera - onmouseout callback is not invoked when page
+ // content changes dinamically and mouse pointer goes out of an element.
+ this.src = imgPath +
+ (getCellInfo(this.id).expanded ? "arrows_light.gif"
+ : "ellipses_light.gif");
+ }
+ expander.onmouseover = function() {
+ this.src = imgPath +
+ (getCellInfo(this.id).expanded ? "arrows_dark.gif"
+ : "ellipses_dark.gif");
+ }
+ expander.onmouseout = function() {
+ this.src = imgPath +
+ (getCellInfo(this.id).expanded ? "arrows_light.gif"
+ : "ellipses_light.gif");
+ }
+
+ expandableDiv.innerHTML = "";
+ expandableDiv.appendChild(data);
+ expandableDiv.appendChild(expander);
+ expandableDiv.style.height = CLIP_HEIGHT + "px";
+ expandableDiv.id = "cell"+ idxStr;
+
+ // Keep original cell height and its ecpanded/cpllapsed state.
+ if (!newGroupCreated) {
+ CellsInfo[groupCount] = [];
+ newGroupCreated = true;
+ }
+ CellsInfo[groupCount][cellCount] = { 'height' : originalHeight,
+ 'expanded' : false };
+ cellCount += 1;
+ }
+ groupCount += newGroupCreated ? 1 : 0;
+ }
+}
+
+function isElemTopVisible(elem) {
+ var body = document.body,
+ html = document.documentElement,
+ // Calculate expandableDiv absolute Y coordinate from the top of body.
+ bodyRect = body.getBoundingClientRect(),
+ elemRect = elem.getBoundingClientRect(),
+ elemOffset = Math.floor(elemRect.top - bodyRect.top),
+ // Calculate the absoute Y coordinate of visible area.
+ scrollTop = html.scrollTop || body && body.scrollTop || 0;
+ scrollTop -= html.clientTop; // IE<8
+
+
+ if (elemOffset < scrollTop)
+ return false;
+
+ return true;
+}
+
+// Invoked when an expander is pressed; expand/collapse a cell.
+function expandCollapse(id) {
+ var cellInfo = getCellInfo(id);
+ var idx = getCellIdx(id);
+
+ // New height of a row.
+ var newHeight;
+ // Smart page scrolling may be done after collapse.
+ var mayNeedScroll;
+
+ if (cellInfo.expanded) {
+ // Cell is expanded - collapse the row height to CLIP_HEIGHT.
+ newHeight = CLIP_HEIGHT;
+ mayNeedScroll = true;
+ }
+ else {
+ // Cell is collapsed - expand the row height to the cells original height.
+ newHeight = cellInfo.height;
+ mayNeedScroll = false;
+ }
+
+ // Update all cells (height and expanded/collapsed state) in a row according
+ // to the new height of the row.
+ for (var i = 0; i < CellsInfo[idx.group].length; i++) {
+ var idxStr = "_" + idx.group + "_" + i;
+ var expandableDiv = document.getElementById("cell" + idxStr);
+ expandableDiv.style.height = newHeight + "px";
+ var data = document.getElementById("data" + idxStr);
+ var expander = document.getElementById("expander" + idxStr);
+ var state = CellsInfo[idx.group][i];
+
+ if (state.height > newHeight) {
+ // Cell height exceeds row height - collapse a cell.
+ data.style.height = (newHeight - EXPANDER_HEIGHT) + "px";
+ expander.src = imgPath + "ellipses_light.gif";
+ CellsInfo[idx.group][i].expanded = false;
+ } else {
+ // Cell height is less then or equal to row height - expand a cell.
+ data.style.height = "";
+ expander.src = imgPath + "arrows_light.gif";
+ CellsInfo[idx.group][i].expanded = true;
+ }
+ }
+
+ if (mayNeedScroll) {
+ var idxStr = "_" + idx.group + "_" + idx.cell;
+ var clickedExpandableDiv = document.getElementById("cell" + idxStr);
+ // Scroll page up if a row is collapsed and the rows top is above the
+ // viewport. The amount of scroll is the difference between a new and old
+ // row height.
+ if (!isElemTopVisible(clickedExpandableDiv)) {
+ window.scrollBy(0, newHeight - cellInfo.height);
+ }
+ }
+}