Skip to content

Commit 6a399bf

Browse files
committed
[analyzer] Implemented RangeSet::Factory::unite function to handle intersections and adjacency
Summary: Handle intersected and adjacent ranges uniting them into a single one. Example: intersection [0, 10] U [5, 20] = [0, 20] adjacency [0, 10] U [11, 20] = [0, 20] Differential Revision: https://reviews.llvm.org/D99797
1 parent a93b179 commit 6a399bf

File tree

3 files changed

+508
-58
lines changed

3 files changed

+508
-58
lines changed

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,30 @@ class RangeSet {
140140
/// Complexity: O(N)
141141
/// where N = size(Original)
142142
RangeSet add(RangeSet Original, const llvm::APSInt &Point);
143+
/// Create a new set which is a union of two given ranges.
144+
/// Possible intersections are not checked here.
145+
///
146+
/// Complexity: O(N + M)
147+
/// where N = size(LHS), M = size(RHS)
148+
RangeSet unite(RangeSet LHS, RangeSet RHS);
149+
/// Create a new set by uniting given range set with the given range.
150+
/// All intersections and adjacent ranges are handled here.
151+
///
152+
/// Complexity: O(N)
153+
/// where N = size(Original)
154+
RangeSet unite(RangeSet Original, Range Element);
155+
/// Create a new set by uniting given range set with the given point.
156+
/// All intersections and adjacent ranges are handled here.
157+
///
158+
/// Complexity: O(N)
159+
/// where N = size(Original)
160+
RangeSet unite(RangeSet Original, llvm::APSInt Point);
161+
/// Create a new set by uniting given range set with the given range
162+
/// between points. All intersections and adjacent ranges are handled here.
163+
///
164+
/// Complexity: O(N)
165+
/// where N = size(Original)
166+
RangeSet unite(RangeSet Original, llvm::APSInt From, llvm::APSInt To);
143167

144168
RangeSet getEmptySet() { return &EmptySet; }
145169

@@ -224,6 +248,9 @@ class RangeSet {
224248
ContainerType *construct(ContainerType &&From);
225249

226250
RangeSet intersect(const ContainerType &LHS, const ContainerType &RHS);
251+
/// NOTE: This function relies on the fact that all values in the
252+
/// containers are persistent (created via BasicValueFactory::getValue).
253+
ContainerType unite(const ContainerType &LHS, const ContainerType &RHS);
227254

228255
// Many operations include producing new APSInt values and that's why
229256
// we need this factory.

clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp

Lines changed: 190 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,14 @@ class OperatorRelationsTable {
110110

111111
RangeSet::ContainerType RangeSet::Factory::EmptySet{};
112112

113+
RangeSet RangeSet::Factory::add(RangeSet LHS, RangeSet RHS) {
114+
ContainerType Result;
115+
Result.reserve(LHS.size() + RHS.size());
116+
std::merge(LHS.begin(), LHS.end(), RHS.begin(), RHS.end(),
117+
std::back_inserter(Result));
118+
return makePersistent(std::move(Result));
119+
}
120+
113121
RangeSet RangeSet::Factory::add(RangeSet Original, Range Element) {
114122
ContainerType Result;
115123
Result.reserve(Original.size() + 1);
@@ -126,6 +134,186 @@ RangeSet RangeSet::Factory::add(RangeSet Original, const llvm::APSInt &Point) {
126134
return add(Original, Range(Point));
127135
}
128136

137+
RangeSet RangeSet::Factory::unite(RangeSet LHS, RangeSet RHS) {
138+
ContainerType Result = unite(*LHS.Impl, *RHS.Impl);
139+
return makePersistent(std::move(Result));
140+
}
141+
142+
RangeSet RangeSet::Factory::unite(RangeSet Original, Range R) {
143+
ContainerType Result;
144+
Result.push_back(R);
145+
Result = unite(*Original.Impl, Result);
146+
return makePersistent(std::move(Result));
147+
}
148+
149+
RangeSet RangeSet::Factory::unite(RangeSet Original, llvm::APSInt Point) {
150+
return unite(Original, Range(ValueFactory.getValue(Point)));
151+
}
152+
153+
RangeSet RangeSet::Factory::unite(RangeSet Original, llvm::APSInt From,
154+
llvm::APSInt To) {
155+
return unite(Original,
156+
Range(ValueFactory.getValue(From), ValueFactory.getValue(To)));
157+
}
158+
159+
template <typename T>
160+
void swapIterators(T &First, T &FirstEnd, T &Second, T &SecondEnd) {
161+
std::swap(First, Second);
162+
std::swap(FirstEnd, SecondEnd);
163+
}
164+
165+
RangeSet::ContainerType RangeSet::Factory::unite(const ContainerType &LHS,
166+
const ContainerType &RHS) {
167+
if (LHS.empty())
168+
return RHS;
169+
if (RHS.empty())
170+
return LHS;
171+
172+
using llvm::APSInt;
173+
using iterator = ContainerType::const_iterator;
174+
175+
iterator First = LHS.begin();
176+
iterator FirstEnd = LHS.end();
177+
iterator Second = RHS.begin();
178+
iterator SecondEnd = RHS.end();
179+
APSIntType Ty = APSIntType(First->From());
180+
const APSInt Min = Ty.getMinValue();
181+
182+
// Handle a corner case first when both range sets start from MIN.
183+
// This helps to avoid complicated conditions below. Specifically, this
184+
// particular check for `MIN` is not needed in the loop below every time
185+
// when we do `Second->From() - One` operation.
186+
if (Min == First->From() && Min == Second->From()) {
187+
if (First->To() > Second->To()) {
188+
// [ First ]--->
189+
// [ Second ]----->
190+
// MIN^
191+
// The Second range is entirely inside the First one.
192+
193+
// Check if Second is the last in its RangeSet.
194+
if (++Second == SecondEnd)
195+
// [ First ]--[ First + 1 ]--->
196+
// [ Second ]--------------------->
197+
// MIN^
198+
// The Union is equal to First's RangeSet.
199+
return LHS;
200+
} else {
201+
// case 1: [ First ]----->
202+
// case 2: [ First ]--->
203+
// [ Second ]--->
204+
// MIN^
205+
// The First range is entirely inside or equal to the Second one.
206+
207+
// Check if First is the last in its RangeSet.
208+
if (++First == FirstEnd)
209+
// [ First ]----------------------->
210+
// [ Second ]--[ Second + 1 ]---->
211+
// MIN^
212+
// The Union is equal to Second's RangeSet.
213+
return RHS;
214+
}
215+
}
216+
217+
const APSInt One = Ty.getValue(1);
218+
ContainerType Result;
219+
220+
// This is called when there are no ranges left in one of the ranges.
221+
// Append the rest of the ranges from another range set to the Result
222+
// and return with that.
223+
const auto AppendTheRest = [&Result](iterator I, iterator E) {
224+
Result.append(I, E);
225+
return Result;
226+
};
227+
228+
while (true) {
229+
// We want to keep the following invariant at all times:
230+
// ---[ First ------>
231+
// -----[ Second --->
232+
if (First->From() > Second->From())
233+
swapIterators(First, FirstEnd, Second, SecondEnd);
234+
235+
// The Union definitely starts with First->From().
236+
// ----------[ First ------>
237+
// ------------[ Second --->
238+
// ----------[ Union ------>
239+
// UnionStart^
240+
const llvm::APSInt &UnionStart = First->From();
241+
242+
// Loop where the invariant holds.
243+
while (true) {
244+
// Skip all enclosed ranges.
245+
// ---[ First ]--->
246+
// -----[ Second ]--[ Second + 1 ]--[ Second + N ]----->
247+
while (First->To() >= Second->To()) {
248+
// Check if Second is the last in its RangeSet.
249+
if (++Second == SecondEnd) {
250+
// Append the Union.
251+
// ---[ Union ]--->
252+
// -----[ Second ]----->
253+
// --------[ First ]--->
254+
// UnionEnd^
255+
Result.emplace_back(UnionStart, First->To());
256+
// ---[ Union ]----------------->
257+
// --------------[ First + 1]--->
258+
// Append all remaining ranges from the First's RangeSet.
259+
return AppendTheRest(++First, FirstEnd);
260+
}
261+
}
262+
263+
// Check if First and Second are disjoint. It means that we find
264+
// the end of the Union. Exit the loop and append the Union.
265+
// ---[ First ]=------------->
266+
// ------------=[ Second ]--->
267+
// ----MinusOne^
268+
if (First->To() < Second->From() - One)
269+
break;
270+
271+
// First is entirely inside the Union. Go next.
272+
// ---[ Union ----------->
273+
// ---- [ First ]-------->
274+
// -------[ Second ]----->
275+
// Check if First is the last in its RangeSet.
276+
if (++First == FirstEnd) {
277+
// Append the Union.
278+
// ---[ Union ]--->
279+
// -----[ First ]------->
280+
// --------[ Second ]--->
281+
// UnionEnd^
282+
Result.emplace_back(UnionStart, Second->To());
283+
// ---[ Union ]------------------>
284+
// --------------[ Second + 1]--->
285+
// Append all remaining ranges from the Second's RangeSet.
286+
return AppendTheRest(++Second, SecondEnd);
287+
}
288+
289+
// We know that we are at one of the two cases:
290+
// case 1: --[ First ]--------->
291+
// case 2: ----[ First ]------->
292+
// --------[ Second ]---------->
293+
// In both cases First starts after Second->From().
294+
// Make sure that the loop invariant holds.
295+
swapIterators(First, FirstEnd, Second, SecondEnd);
296+
}
297+
298+
// Here First and Second are disjoint.
299+
// Append the Union.
300+
// ---[ Union ]--------------->
301+
// -----------------[ Second ]--->
302+
// ------[ First ]--------------->
303+
// UnionEnd^
304+
Result.emplace_back(UnionStart, First->To());
305+
306+
// Check if First is the last in its RangeSet.
307+
if (++First == FirstEnd)
308+
// ---[ Union ]--------------->
309+
// --------------[ Second ]--->
310+
// Append all remaining ranges from the Second's RangeSet.
311+
return AppendTheRest(Second, SecondEnd);
312+
}
313+
314+
llvm_unreachable("Normally, we should not reach here");
315+
}
316+
129317
RangeSet RangeSet::Factory::getRangeSet(Range From) {
130318
ContainerType Result;
131319
Result.push_back(From);
@@ -155,13 +343,6 @@ RangeSet::ContainerType *RangeSet::Factory::construct(ContainerType &&From) {
155343
return new (Buffer) ContainerType(std::move(From));
156344
}
157345

158-
RangeSet RangeSet::Factory::add(RangeSet LHS, RangeSet RHS) {
159-
ContainerType Result;
160-
std::merge(LHS.begin(), LHS.end(), RHS.begin(), RHS.end(),
161-
std::back_inserter(Result));
162-
return makePersistent(std::move(Result));
163-
}
164-
165346
const llvm::APSInt &RangeSet::getMinValue() const {
166347
assert(!isEmpty());
167348
return begin()->From();
@@ -325,11 +506,6 @@ RangeSet RangeSet::Factory::intersect(const RangeSet::ContainerType &LHS,
325506
const_iterator First = LHS.begin(), Second = RHS.begin(),
326507
FirstEnd = LHS.end(), SecondEnd = RHS.end();
327508

328-
const auto SwapIterators = [&First, &FirstEnd, &Second, &SecondEnd]() {
329-
std::swap(First, Second);
330-
std::swap(FirstEnd, SecondEnd);
331-
};
332-
333509
// If we ran out of ranges in one set, but not in the other,
334510
// it means that those elements are definitely not in the
335511
// intersection.
@@ -339,7 +515,7 @@ RangeSet RangeSet::Factory::intersect(const RangeSet::ContainerType &LHS,
339515
// ----[ First ---------------------->
340516
// --------[ Second ----------------->
341517
if (Second->From() < First->From())
342-
SwapIterators();
518+
swapIterators(First, FirstEnd, Second, SecondEnd);
343519

344520
// Loop where the invariant holds:
345521
do {
@@ -373,7 +549,7 @@ RangeSet RangeSet::Factory::intersect(const RangeSet::ContainerType &LHS,
373549
if (Second->To() > First->To()) {
374550
// Here we make a decision to keep First as the "longer"
375551
// range.
376-
SwapIterators();
552+
swapIterators(First, FirstEnd, Second, SecondEnd);
377553
}
378554

379555
// At this point, we have the following situation:

0 commit comments

Comments
 (0)