Skip to content

Commit dd65d96

Browse files
committed
C#: Introduce a Location extension method to help pick a unique location.
1 parent abc7cc3 commit dd65d96

File tree

1 file changed

+45
-1
lines changed

1 file changed

+45
-1
lines changed

csharp/extractor/Semmle.Extraction/LocationExtensions.cs

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
using Microsoft.CodeAnalysis;
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using Microsoft.CodeAnalysis;
25

36
namespace Semmle.Extraction
47
{
@@ -36,5 +39,46 @@ public static bool Before(this Location before, Location after)
3639
var endsBefore = before.SourceSpan.End <= after.SourceSpan.Start;
3740
return sameFile && endsBefore;
3841
}
42+
43+
private static int GetLocationKindPriority(Location location) =>
44+
location.IsInSource
45+
? 2
46+
: location.IsInMetadata
47+
? 1
48+
: 0;
49+
50+
/// <summary>
51+
/// Returns true if l1 is better than l2.
52+
/// Source locations are considered better than non source locations.
53+
/// </summary>
54+
private static bool BetterThan(Location l1, Location l2)
55+
{
56+
if (GetLocationKindPriority(l1) > GetLocationKindPriority(l2))
57+
{
58+
return true;
59+
}
60+
61+
// For source locations we compare the filepath and span.
62+
if (l1.IsInSource && l2.IsInSource)
63+
{
64+
var l1s = l1.SourceTree.FilePath + l1.SourceSpan;
65+
var l2s = l2.SourceTree.FilePath + l2.SourceSpan;
66+
return l1s.CompareTo(l2s) < 0;
67+
}
68+
69+
return false;
70+
}
71+
72+
/// <summary>
73+
/// Returns the best location from the given list of locations.
74+
/// Source locations are considered better than non-source locations.
75+
/// In case of a (source location) tie, the location with the
76+
/// lexicographically smaller filepath and span is considered better.
77+
/// </summary>
78+
public static Location? BestOrDefault(this IEnumerable<Location> locations) =>
79+
locations.Any() ? locations.Aggregate((best, loc) => BetterThan(best, loc) ? best : loc) : null;
80+
81+
public static Location Best(this IEnumerable<Location> locations) =>
82+
locations.BestOrDefault() ?? throw new ArgumentException("No location found.");
3983
}
4084
}

0 commit comments

Comments
 (0)