[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-18 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ planned changes to this revision.
NoQ added a comment.

Todo:

- See if the extra __kindofs leak into diagnostic messages.
- Test how this behaves in cases (2) and (4), add tests.
- Add tests for the recursive `__kindof` specifier merge (i.e. properly merge 
the second `__kindof` in `NSSet<__kindof NSArray<__kindof NSString>>`).


https://reviews.llvm.org/D33191



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-18 Thread Gábor Horváth via Phabricator via cfe-commits
xazax.hun added a comment.

In https://reviews.llvm.org/D33191#758583, @NoQ wrote:

> I think i found a relatively clean way of storing the kindof specifiers, 
> which is within the most-specialized type object itself.
>
> Like, if we see `Foo` being casted to `Foo<__kindof X, Y>` and in 
> another place to `Foo`, then we'd store `Foo<__kindof X, 
> __kindof Y>` in our map.


Great idea! I also think this approach is superior to the previous one.


https://reviews.llvm.org/D33191



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-18 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ updated this revision to Diff 99444.
NoQ added a comment.

Added a bit more info in the code comments.


https://reviews.llvm.org/D33191

Files:
  lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
  test/Analysis/generics.m

Index: test/Analysis/generics.m
===
--- test/Analysis/generics.m
+++ test/Analysis/generics.m
@@ -390,6 +390,39 @@
   [arrayOfStrings containsObject:someString]; // no-warning
 }
 
+NSArray *getStringMutableArray() {
+  NSMutableArray *arr = [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray *getStringMutableArraySpecialized() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray<__kindof NSString *> *getKindofStringMutableArray() {
+  NSMutableArray *arr = [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray<__kindof NSString *> *getKindofStringMutableArraySpecialized() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+void testKindofPropagation() {
+  NSArray *arr1 =
+  (NSArray *)getKindofStringMutableArray(); // no-warning
+  NSArray *arr2 =
+  (NSArray *)getKindofStringMutableArraySpecialized(); // no-warning
+  NSArray *arr3 =
+  (NSArray *)getStringMutableArray(); // expected-warning{{Conversion from value of type 'NSMutableArray *' to incompatible type 'NSArray *'}}
+  NSArray *arr4 =
+  (NSArray *)getStringMutableArraySpecialized(); // expected-warning{{Conversion from value of type 'NSMutableArray *' to incompatible type 'NSArray *'}}
+}
+
 // CHECK:  diagnostics
 // CHECK-NEXT:  
 // CHECK-NEXT:   
@@ -7140,4 +7173,644 @@
 // CHECK-NEXT:file0
 // CHECK-NEXT:   
 // CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:path
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line416
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line416
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line421
+// CHECK-NEXT:col37
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line421
+// CHECK-NEXT:col57
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindevent
+// CHECK-NEXT:  location
+// CHECK-NEXT:  
+// CHECK-NEXT:   line421
+// CHECK-NEXT:   col37
+// CHECK-NEXT:   file0
+// CHECK-NEXT:  
+// CHECK-NEXT:  ranges
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  line421
+// CHECK-NEXT:  col37
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  line421
+// CHECK-NEXT:  col59
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT:
+// CHECK-NEXT:  
+// CHECK-NEXT:  depth0
+// CHECK-NEXT:  extended_message
+// CHECK-NEXT:  Calling getStringMutableArray
+// CHECK-NEXT:  message
+// CHECK-NEXT:  Calling getStringMutableArray
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindevent
+// CHECK-NEXT:  location
+// CHECK-NEXT:  
+// CHECK-NEXT:   line393
+// CHECK-NEXT:   col1
+// CHECK-NEXT:   file0
+// CHECK-NEXT:  
+// CHECK-NEXT:  depth1
+// CHECK-NEXT:  extended_message
+// CHECK-NEXT:  Entered call from testKindofPropagation
+// CHECK-NEXT:  message
+// CHECK-NEXT:  Entered call from 

[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-18 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ updated this revision to Diff 99443.
NoQ added a comment.

I think i found a relatively clean way of storing the kindof specifiers, which 
is within the most-specialized type object itself.

Like, if we see `Foo` being casted to `Foo<__kindof X, Y>` and in another 
place to `Foo`, then we'd store `Foo<__kindof X, __kindof Y>` in 
our map.


https://reviews.llvm.org/D33191

Files:
  lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
  test/Analysis/generics.m

Index: test/Analysis/generics.m
===
--- test/Analysis/generics.m
+++ test/Analysis/generics.m
@@ -390,6 +390,39 @@
   [arrayOfStrings containsObject:someString]; // no-warning
 }
 
+NSArray *getStringMutableArray() {
+  NSMutableArray *arr = [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray *getStringMutableArraySpecialized() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray<__kindof NSString *> *getKindofStringMutableArray() {
+  NSMutableArray *arr = [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray<__kindof NSString *> *getKindofStringMutableArraySpecialized() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+void testKindofPropagation() {
+  NSArray *arr1 =
+  (NSArray *)getKindofStringMutableArray(); // no-warning
+  NSArray *arr2 =
+  (NSArray *)getKindofStringMutableArraySpecialized(); // no-warning
+  NSArray *arr3 =
+  (NSArray *)getStringMutableArray(); // expected-warning{{Conversion from value of type 'NSMutableArray *' to incompatible type 'NSArray *'}}
+  NSArray *arr4 =
+  (NSArray *)getStringMutableArraySpecialized(); // expected-warning{{Conversion from value of type 'NSMutableArray *' to incompatible type 'NSArray *'}}
+}
+
 // CHECK:  diagnostics
 // CHECK-NEXT:  
 // CHECK-NEXT:   
@@ -7140,4 +7173,644 @@
 // CHECK-NEXT:file0
 // CHECK-NEXT:   
 // CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:path
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line416
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line416
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line421
+// CHECK-NEXT:col37
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line421
+// CHECK-NEXT:col57
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindevent
+// CHECK-NEXT:  location
+// CHECK-NEXT:  
+// CHECK-NEXT:   line421
+// CHECK-NEXT:   col37
+// CHECK-NEXT:   file0
+// CHECK-NEXT:  
+// CHECK-NEXT:  ranges
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  line421
+// CHECK-NEXT:  col37
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  line421
+// CHECK-NEXT:  col59
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT:
+// CHECK-NEXT:  
+// CHECK-NEXT:  depth0
+// CHECK-NEXT:  extended_message
+// CHECK-NEXT:  Calling getStringMutableArray
+// CHECK-NEXT:  message
+// CHECK-NEXT:  Calling getStringMutableArray
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindevent
+// CHECK-NEXT:  location
+// CHECK-NEXT:  
+// CHECK-NEXT:   line393
+// CHECK-NEXT:   col1
+// 

[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-17 Thread Anna Zaks via Phabricator via cfe-commits
zaks.anna added inline comments.



Comment at: lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp:464
  ASTContext ) {
+  if (hasKindofArgs(StaticUpperBound)) {
+// If the upper bound type has more __kindof specs, we drop all the info,

I am concerned that this might cause regressions as other logic in this 
function is not triggered when this condition fires. For example, this would 
only be safe if Current and StaticUpperBoound are the same type apart from 
__kindof modifier.


https://reviews.llvm.org/D33191



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-17 Thread Gábor Horváth via Phabricator via cfe-commits
xazax.hun added a comment.

In https://reviews.llvm.org/D33191#756174, @NoQ wrote:

> @Gábor: I didn't want to bother you with this, but i'm not entirely sure 
> about how to deal with these false positives; since you're the original 
> author of this check, if you see anything obviously wrong here please comment 
> on me :)


I do not see anything obviously wrong. Of course this approach is very 
conservative, but in order to do it less conservatively probably we would need 
to store the type information separately for every type argument. Converting to 
that approach would be a lot of work, and it might make the check more complex.


https://reviews.llvm.org/D33191



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-16 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ updated this revision to Diff 99150.
NoQ added a comment.

Cover more cases and be more conservative.

@Gábor: I didn't want to bother you with this, but i'm not entirely sure about 
how to deal with these false positives; since you're the original author of 
this check, if you see anything obviously wrong here please comment on me :)


https://reviews.llvm.org/D33191

Files:
  lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
  test/Analysis/generics.m

Index: test/Analysis/generics.m
===
--- test/Analysis/generics.m
+++ test/Analysis/generics.m
@@ -390,6 +390,39 @@
   [arrayOfStrings containsObject:someString]; // no-warning
 }
 
+NSArray *getStringMutableArray() {
+  NSMutableArray *arr = [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray *getStringMutableArraySpecialized() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray<__kindof NSString *> *getKindofStringMutableArray() {
+  NSMutableArray *arr = [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray<__kindof NSString *> *getKindofStringMutableArraySpecialized() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+void testKindofPropagation() {
+  NSArray *arr1 =
+  (NSArray *)getKindofStringMutableArray(); // no-warning
+  NSArray *arr2 =
+  (NSArray *)getKindofStringMutableArraySpecialized(); // no-warning
+  NSArray *arr3 =
+  (NSArray *)getStringMutableArray(); // expected-warning{{Conversion from value of type 'NSMutableArray *' to incompatible type 'NSArray *'}}
+  NSArray *arr4 =
+  (NSArray *)getStringMutableArraySpecialized(); // expected-warning{{Conversion from value of type 'NSMutableArray *' to incompatible type 'NSArray *'}}
+}
+
 // CHECK:  diagnostics
 // CHECK-NEXT:  
 // CHECK-NEXT:   
@@ -7140,4 +7173,644 @@
 // CHECK-NEXT:file0
 // CHECK-NEXT:   
 // CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:path
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line416
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line416
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line420
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line421
+// CHECK-NEXT:col37
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line421
+// CHECK-NEXT:col57
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindevent
+// CHECK-NEXT:  location
+// CHECK-NEXT:  
+// CHECK-NEXT:   line421
+// CHECK-NEXT:   col37
+// CHECK-NEXT:   file0
+// CHECK-NEXT:  
+// CHECK-NEXT:  ranges
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  line421
+// CHECK-NEXT:  col37
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  line421
+// CHECK-NEXT:  col59
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT:
+// CHECK-NEXT:  
+// CHECK-NEXT:  depth0
+// CHECK-NEXT:  extended_message
+// CHECK-NEXT:  Calling getStringMutableArray
+// CHECK-NEXT:  message
+// CHECK-NEXT:  Calling getStringMutableArray
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindevent
+// CHECK-NEXT:  location
+// CHECK-NEXT:  
+// CHECK-NEXT:   line393
+// CHECK-NEXT:   col1
+// CHECK-NEXT:   file0

[PATCH] D33191: [analyzer] ObjCGenerics: account for __kindof specifiers met along a chain of casts.

2017-05-15 Thread Artem Dergachev via Phabricator via cfe-commits
NoQ created this revision.
Herald added a subscriber: xazax.hun.

`__kindof` type specifiers allow the developers to express their intent in 
discriminating between generic type arguments being matched exactly or allowing 
sub-types. When generics were introduced, it was already too late to add 
`__kindof` specifiers consistently across all the code. So for now in most code 
we believe it's all right not to have them, but we need to expect to have them 
at least in some places (which would normally be API declarations) and pick 
them up when they're present by loosening our dynamic type information from 
non-`__kindof` to `__kindof`, which would suppress some of the false "invalid 
cast" warnings.

In the test provided, the `__kindof` is only present on the API return value; 
direct cast from the object created within the callee function is an error, 
however casting indirectly through a `__kindof` type should be possible, 
because just one `__kindof` annotation at the API declaration is considered to 
be enough to express the intent of "it was `__kindof` from the start but we 
didn't bother adding it".

For now, we discard the original type information when we find `__kindof` 
specifiers in a chain of casts.


https://reviews.llvm.org/D33191

Files:
  lib/StaticAnalyzer/Checkers/DynamicTypePropagation.cpp
  test/Analysis/generics.m

Index: test/Analysis/generics.m
===
--- test/Analysis/generics.m
+++ test/Analysis/generics.m
@@ -390,6 +390,25 @@
   [arrayOfStrings containsObject:someString]; // no-warning
 }
 
+NSArray *getStringMutableArray() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+NSArray<__kindof NSString *> *getKindofStringMutableArray() {
+  NSMutableArray *arr =
+  [[NSMutableArray alloc] init];
+  return arr;
+}
+
+void testKindofPropagation() {
+  NSArray *arr1 =
+  (NSArray *)getKindofStringMutableArray(); // no-warning
+  NSArray *arr2 =
+  (NSArray *)getStringMutableArray(); // expected-warning{{Conversion from value of type 'NSMutableArray *' to incompatible type 'NSArray *'}}
+}
+
 // CHECK:  diagnostics
 // CHECK-NEXT:  
 // CHECK-NEXT:   
@@ -7140,4 +7159,324 @@
 // CHECK-NEXT:file0
 // CHECK-NEXT:   
 // CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:path
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line406
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line406
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line408
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line408
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindcontrol
+// CHECK-NEXT:  edges
+// CHECK-NEXT:   
+// CHECK-NEXT:
+// CHECK-NEXT: start
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line408
+// CHECK-NEXT:col3
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line408
+// CHECK-NEXT:col9
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT: end
+// CHECK-NEXT:  
+// CHECK-NEXT:   
+// CHECK-NEXT:line409
+// CHECK-NEXT:col37
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:   
+// CHECK-NEXT:line409
+// CHECK-NEXT:col57
+// CHECK-NEXT:file0
+// CHECK-NEXT:   
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT:   
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  kindevent
+// CHECK-NEXT:  location
+// CHECK-NEXT:  
+// CHECK-NEXT:   line409
+// CHECK-NEXT:   col37
+// CHECK-NEXT:   file0
+// CHECK-NEXT:  
+// CHECK-NEXT:  ranges
+// CHECK-NEXT:  
+// CHECK-NEXT:
+// CHECK-NEXT: 
+// CHECK-NEXT:  line409
+// CHECK-NEXT:  col37
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT: 
+// CHECK-NEXT:  line409
+// CHECK-NEXT:  col59
+// CHECK-NEXT:  file0
+// CHECK-NEXT: 
+// CHECK-NEXT:
+// CHECK-NEXT:  
+// CHECK-NEXT:  depth0
+// CHECK-NEXT: