@@ -110,35 +110,89 @@ class SourceLocation extends Location, @location_default {
110
110
111
111
bindingset [ version]
112
112
private int versionField ( string version , int field ) {
113
- exists ( string format |
114
- format = "(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)" or
115
- format = "(\\d+)\\.(\\d+)\\.(\\d+)" or
116
- format = "(\\d+)\\.(\\d+)"
113
+ exists ( string format , int i |
114
+ format = "(\\d+)\\.(\\d+)\\.(\\d+)\\.(\\d+)|" + "(\\d+)\\.(\\d+)\\.(\\d+)|" + "(\\d+)\\.(\\d+)" and
115
+ result = version .regexpCapture ( format , i ) .toInt ( )
117
116
|
118
- result = version .regexpCapture ( format , field ) .toInt ( )
117
+ i = [ 1 , 5 , 8 ] and
118
+ field = 1
119
+ or
120
+ i = [ 2 , 6 , 9 ] and
121
+ field = 2
122
+ or
123
+ i = [ 3 , 7 ] and
124
+ field = 3
125
+ or
126
+ i = 4 and
127
+ field = 4
119
128
) and
120
129
result >= 0 and
121
130
result <= 255
122
131
}
123
132
124
133
/** An assembly version, for example `4.0.0.0` or `4.5`. */
125
134
class Version extends string {
135
+ private int major ;
136
+
126
137
bindingset [ this ]
127
- Version ( ) { exists ( versionField ( this , 1 ) ) }
138
+ Version ( ) { major = versionField ( this , 1 ) }
139
+
140
+ bindingset [ this ]
141
+ private int getVersionField ( int field ) {
142
+ field = 1 and
143
+ result = major
144
+ or
145
+ field in [ 2 .. 4 ] and
146
+ result = versionField ( this , field )
147
+ }
128
148
129
149
/**
130
150
* Gets field `field` of this version.
131
151
* If the field is unspecified in the version string, then the result is `0`.
132
152
*/
133
153
bindingset [ this ]
134
154
int getField ( int field ) {
135
- field in [ 1 .. 4 ] and
136
- if exists ( versionField ( this , field ) ) then result = versionField ( this , field ) else result = 0
155
+ result = this .getVersionField ( field )
156
+ or
157
+ field in [ 2 .. 4 ] and
158
+ not exists ( this .getVersionField ( field ) ) and
159
+ result = 0
160
+ }
161
+
162
+ bindingset [ this ]
163
+ private string getCanonicalizedField ( int field ) {
164
+ exists ( string s , int length |
165
+ s = this .getVersionField ( field ) .toString ( ) and
166
+ length = s .length ( )
167
+ |
168
+ // make each field consist of 3 digits
169
+ result = concat ( int i | i in [ 1 .. 3 - length ] | "0" ) + s
170
+ )
171
+ }
172
+
173
+ /**
174
+ * Gets a canonicalized version of this string, where lexicographical ordering
175
+ * corresponds to version ordering.
176
+ */
177
+ bindingset [ this ]
178
+ string getCanonicalizedVersion ( ) {
179
+ exists ( string res , int length |
180
+ res =
181
+ strictconcat ( int field , string s |
182
+ s = this .getCanonicalizedField ( field )
183
+ |
184
+ s , "." order by field
185
+ ) and
186
+ length = res .length ( )
187
+ |
188
+ // make each canonicalized version consist of 4 chunks of 3 digits separated by a dot
189
+ result = res + concat ( int i | i = [ 1 .. 15 - length ] / 4 and i > 0 | ".000" )
190
+ )
137
191
}
138
192
139
193
/** Gets the major version, for example `1` in `1.2.3.4`. */
140
194
bindingset [ this ]
141
- int getMajor ( ) { result = this . getField ( 1 ) }
195
+ int getMajor ( ) { result = major }
142
196
143
197
/** Gets the major revision, for example `2` in `1.2.3.4`. */
144
198
bindingset [ this ]
@@ -164,9 +218,7 @@ class Version extends string {
164
218
*/
165
219
bindingset [ this , other]
166
220
predicate isEarlierThan ( Version other ) {
167
- exists ( int i | this .getField ( i ) < other .getField ( i ) |
168
- forall ( int j | j in [ 1 .. i - 1 ] | this .getField ( j ) = other .getField ( j ) )
169
- )
221
+ this .getCanonicalizedVersion ( ) < other .getCanonicalizedVersion ( )
170
222
}
171
223
172
224
/**
0 commit comments