From 9d07336c759c51fd09fcaf8a32c04a9dfcda84b0 Mon Sep 17 00:00:00 2001 From: Michael Schneider Date: Mon, 18 Apr 2016 14:38:32 -0700 Subject: [PATCH] Fix static analyzer issue with common indexes algorithm in _asdk_commonIndexesWithArray: The issue was: The left operand of '>=' is a garbage value in else if check for lengths[i+1][j] ... I had to rewrite the algorithm to quiet the static analyzer. --- AsyncDisplayKit/Private/NSArray+Diffing.m | 34 +++++++++------- AsyncDisplayKitTests/ArrayDiffingTests.m | 47 ++++++++++++++++++++++- 2 files changed, 66 insertions(+), 15 deletions(-) diff --git a/AsyncDisplayKit/Private/NSArray+Diffing.m b/AsyncDisplayKit/Private/NSArray+Diffing.m index f0989f8dd1..837d1ed25d 100644 --- a/AsyncDisplayKit/Private/NSArray+Diffing.m +++ b/AsyncDisplayKit/Private/NSArray+Diffing.m @@ -50,30 +50,36 @@ - (NSIndexSet *)_asdk_commonIndexesWithArray:(NSArray *)array compareBlock:(BOOL (^)(id lhs, id rhs))comparison { NSAssert(comparison != nil, @"Comparison block is required"); - NSInteger lengths[self.count+1][array.count+1]; - for (NSInteger i = self.count; i >= 0; i--) { - for (NSInteger j = array.count; j >= 0; j--) { - if (i == self.count || j == array.count) { + + NSInteger selfCount = self.count; + NSInteger arrayCount = array.count; + + NSInteger lengths[selfCount+1][arrayCount+1]; + for (NSInteger i = 0; i <= selfCount; i++) { + for (NSInteger j = 0; j <= arrayCount; j++) { + if (i == 0 || j == 0) { lengths[i][j] = 0; - } else if (comparison(self[i], array[j])) { - lengths[i][j] = 1 + lengths[i+1][j+1]; + } else if (comparison(self[i-1], array[j-1])) { + lengths[i][j] = 1 + lengths[i-1][j-1]; } else { - lengths[i][j] = MAX(lengths[i+1][j], lengths[i][j+1]); + lengths[i][j] = MAX(lengths[i-1][j], lengths[i][j-1]); } } } NSMutableIndexSet *common = [NSMutableIndexSet indexSet]; - for (NSInteger i = 0, j = 0; i < self.count && j < array.count;) { - if (comparison(self[i], array[j])) { - [common addIndex:i]; - i++; j++; - } else if (lengths[i+1][j] >= lengths[i][j+1]) { - i++; + NSInteger i = selfCount, j = arrayCount; + while(i > 0 && j > 0) { + if (comparison(self[i-1], array[j-1])) { + [common addIndex:(i-1)]; + i--; j--; + } else if (lengths[i-1][j] > lengths[i][j-1]) { + i--; } else { - j++; + j--; } } + return common; } diff --git a/AsyncDisplayKitTests/ArrayDiffingTests.m b/AsyncDisplayKitTests/ArrayDiffingTests.m index 636af90835..aaac8e4ca1 100644 --- a/AsyncDisplayKitTests/ArrayDiffingTests.m +++ b/AsyncDisplayKitTests/ArrayDiffingTests.m @@ -10,13 +10,58 @@ #import "NSArray+Diffing.h" +@interface NSArray (ArrayDiffingTests) +- (NSIndexSet *)_asdk_commonIndexesWithArray:(NSArray *)array compareBlock:(BOOL (^)(id lhs, id rhs))comparison; +@end + @interface ArrayDiffingTests : XCTestCase @end @implementation ArrayDiffingTests -- (void)testDiffing { +- (void)testDiffingCommonIndexes +{ + NSArray *tests = @[ + @[ + @[@"bob", @"alice", @"dave"], + @[@"bob", @"alice", @"dave", @"gary"], + @[@0, @1, @2] + ], + @[ + @[@"bob", @"alice", @"dave"], + @[@"bob", @"gary", @"dave"], + @[@0, @2] + ], + @[ + @[@"bob", @"alice"], + @[@"gary", @"dave"], + @[], + ], + @[ + @[@"bob", @"alice", @"dave"], + @[], + @[], + ], + @[ + @[], + @[@"bob", @"alice", @"dave"], + @[], + ], + ]; + + for (NSArray *test in tests) { + NSIndexSet *indexSet = [test[0] _asdk_commonIndexesWithArray:test[1] compareBlock:^BOOL(id lhs, id rhs) { + return [lhs isEqual:rhs]; + }]; + + for (NSNumber *index in (NSArray *)test[2]) { + XCTAssert([indexSet containsIndex:[index integerValue]]); + } + } +} + +- (void)testDiffingInsertionsAndDeletions { NSArray *tests = @[ @[ @[@"bob", @"alice", @"dave"],