Skip to content

Commit 15caaa7

Browse files
authored
Merge pull request #7377 from hvitved/csharp/overriable-class
C#: Introduce class `Overridable`
2 parents 861ae85 + a9c4389 commit 15caaa7

File tree

15 files changed

+103
-205
lines changed

15 files changed

+103
-205
lines changed

csharp/ql/lib/semmle/code/csharp/Assignable.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ private class RefArg extends AssignableAccess {
205205
*/
206206
predicate isAnalyzable(Parameter p) {
207207
exists(Callable callable | callable = this.getUnboundDeclarationTarget(p) |
208-
not callable.(Virtualizable).isOverridableOrImplementable() and
208+
not callable.(Overridable).isOverridableOrImplementable() and
209209
callable.hasBody()
210210
)
211211
}

csharp/ql/lib/semmle/code/csharp/Implements.qll

+7-7
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Provides logic for determining interface member implementations.
55
*
66
* Do not use the predicates in this library directly; use the methods
7-
* of the class `Virtualizable` instead.
7+
* of the class `Overridable` instead.
88
*/
99

1010
import csharp
@@ -35,7 +35,7 @@ private import Conversion
3535
* `implements(A.M, I.M, B)` and `implements(C.M, I.M, C)`.
3636
*/
3737
cached
38-
predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
38+
predicate implements(Overridable m1, Overridable m2, ValueOrRefType t) {
3939
exists(Interface i |
4040
i = m2.getDeclaringType() and
4141
t.getABaseInterface+() = i and
@@ -66,7 +66,7 @@ predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
6666
* for type `C`, because `C.M()` conflicts.
6767
*/
6868
pragma[nomagic]
69-
private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m, ValueOrRefType t) {
69+
private Overridable getAnImplementedInterfaceMemberForSubType(Overridable m, ValueOrRefType t) {
7070
result = getACompatibleInterfaceMember(m) and
7171
t = m.getDeclaringType()
7272
or
@@ -78,7 +78,7 @@ private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m,
7878
}
7979

8080
pragma[noinline]
81-
private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Virtualizable m) {
81+
private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Overridable m) {
8282
m = getACompatibleInterfaceMember(t.getAMember())
8383
}
8484

@@ -88,7 +88,7 @@ private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Virtu
8888
* the interface member is accessed.
8989
*/
9090
pragma[nomagic]
91-
private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
91+
private Overridable getACompatibleInterfaceMember(Overridable m) {
9292
result = getACompatibleInterfaceMemberAux(m) and
9393
(
9494
// If there is both an implicit and an explicit compatible member
@@ -100,14 +100,14 @@ private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
100100
}
101101

102102
pragma[nomagic]
103-
private Virtualizable getACompatibleExplicitInterfaceMember(Virtualizable m, ValueOrRefType declType) {
103+
private Overridable getACompatibleExplicitInterfaceMember(Overridable m, ValueOrRefType declType) {
104104
result = getACompatibleInterfaceMemberAux(m) and
105105
declType = m.getDeclaringType() and
106106
m.implementsExplicitInterface()
107107
}
108108

109109
pragma[nomagic]
110-
private Virtualizable getACompatibleInterfaceMemberAux(Virtualizable m) {
110+
private Overridable getACompatibleInterfaceMemberAux(Overridable m) {
111111
result = getACompatibleInterfaceAccessor(m) or
112112
result = getACompatibleInterfaceIndexer(m) or
113113
result = getACompatibleInterfaceMethod(m)

csharp/ql/lib/semmle/code/csharp/Member.qll

+55-41
Original file line numberDiff line numberDiff line change
@@ -180,29 +180,15 @@ class Member extends DotNet::Member, Modifiable, @member {
180180
override predicate isStatic() { Modifiable.super.isStatic() }
181181
}
182182

183+
private class TOverridable = @virtualizable or @callable_accessor;
184+
183185
/**
184-
* A member where the `virtual` modifier is valid. That is, a method,
185-
* a property, an indexer, or an event.
186+
* A declaration that can be overridden or implemented. That is, a method,
187+
* a property, an indexer, an event, or an accessor.
186188
*
187-
* Equivalently, these are the members that can be defined in an interface.
189+
* Unlike `Virtualizable`, this class includes accessors.
188190
*/
189-
class Virtualizable extends Member, @virtualizable {
190-
/** Holds if this member has the modifier `override`. */
191-
predicate isOverride() { this.hasModifier("override") }
192-
193-
/** Holds if this member is `virtual`. */
194-
predicate isVirtual() { this.hasModifier("virtual") }
195-
196-
override predicate isPublic() {
197-
Member.super.isPublic() or
198-
this.implementsExplicitInterface()
199-
}
200-
201-
override predicate isPrivate() {
202-
super.isPrivate() and
203-
not this.implementsExplicitInterface()
204-
}
205-
191+
class Overridable extends Declaration, TOverridable {
206192
/**
207193
* Gets any interface this member explicitly implements; this only applies
208194
* to members that can be declared on an interface, i.e. methods, properties,
@@ -216,19 +202,10 @@ class Virtualizable extends Member, @virtualizable {
216202
predicate implementsExplicitInterface() { exists(this.getExplicitlyImplementedInterface()) }
217203

218204
/** Holds if this member can be overridden or implemented. */
219-
predicate isOverridableOrImplementable() {
220-
not this.isSealed() and
221-
not this.getDeclaringType().isSealed() and
222-
(
223-
this.isVirtual() or
224-
this.isOverride() or
225-
this.isAbstract() or
226-
this.getDeclaringType() instanceof Interface
227-
)
228-
}
205+
predicate isOverridableOrImplementable() { none() }
229206

230207
/** Gets the member that is immediately overridden by this member, if any. */
231-
Virtualizable getOverridee() {
208+
Overridable getOverridee() {
232209
overrides(this, result)
233210
or
234211
// For accessors (which are `Callable`s), the extractor generates entries
@@ -242,7 +219,7 @@ class Virtualizable extends Member, @virtualizable {
242219
}
243220

244221
/** Gets a member that immediately overrides this member, if any. */
245-
Virtualizable getAnOverrider() { this = result.getOverridee() }
222+
Overridable getAnOverrider() { this = result.getOverridee() }
246223

247224
/** Holds if this member is overridden by some other member. */
248225
predicate isOverridden() { exists(this.getAnOverrider()) }
@@ -273,10 +250,10 @@ class Virtualizable extends Member, @virtualizable {
273250
* `A.M.getImplementee(B) = I.M` and
274251
* `C.M.getImplementee(C) = I.M`.
275252
*/
276-
Virtualizable getImplementee(ValueOrRefType t) { implements(this, result, t) }
253+
Overridable getImplementee(ValueOrRefType t) { implements(this, result, t) }
277254

278255
/** Gets the interface member that is immediately implemented by this member, if any. */
279-
Virtualizable getImplementee() { result = this.getImplementee(_) }
256+
Overridable getImplementee() { result = this.getImplementee(_) }
280257

281258
/**
282259
* Gets a member that immediately implements this interface member, if any.
@@ -301,10 +278,10 @@ class Virtualizable extends Member, @virtualizable {
301278
* `I.M.getAnImplementor(B) = A.M` and
302279
* `I.M.getAnImplementor(C) = C.M`.
303280
*/
304-
Virtualizable getAnImplementor(ValueOrRefType t) { this = result.getImplementee(t) }
281+
Overridable getAnImplementor(ValueOrRefType t) { this = result.getImplementee(t) }
305282

306283
/** Gets a member that immediately implements this interface member, if any. */
307-
Virtualizable getAnImplementor() { this = result.getImplementee() }
284+
Overridable getAnImplementor() { this = result.getImplementee() }
308285

309286
/**
310287
* Gets an interface member that is (transitively) implemented by this
@@ -334,8 +311,8 @@ class Virtualizable extends Member, @virtualizable {
334311
* - If this member is `D.M` then `I.M = getAnUltimateImplementee()`.
335312
*/
336313
pragma[nomagic]
337-
Virtualizable getAnUltimateImplementee() {
338-
exists(Virtualizable implementation, ValueOrRefType implementationType |
314+
Overridable getAnUltimateImplementee() {
315+
exists(Overridable implementation, ValueOrRefType implementationType |
339316
implements(implementation, result, implementationType)
340317
|
341318
this = implementation
@@ -354,7 +331,7 @@ class Virtualizable extends Member, @virtualizable {
354331
* Note that this is generally *not* equivalent with
355332
* `getImplementor().getAnOverrider*()` (see `getImplementee`).
356333
*/
357-
Virtualizable getAnUltimateImplementor() { this = result.getAnUltimateImplementee() }
334+
Overridable getAnUltimateImplementor() { this = result.getAnUltimateImplementee() }
358335

359336
/** Holds if this interface member is implemented by some other member. */
360337
predicate isImplemented() { exists(this.getAnImplementor()) }
@@ -366,7 +343,7 @@ class Virtualizable extends Member, @virtualizable {
366343
* Holds if this member overrides or implements (transitively)
367344
* `that` member.
368345
*/
369-
predicate overridesOrImplements(Virtualizable that) {
346+
predicate overridesOrImplements(Overridable that) {
370347
this.getOverridee+() = that or
371348
this.getAnUltimateImplementee() = that
372349
}
@@ -375,12 +352,49 @@ class Virtualizable extends Member, @virtualizable {
375352
* Holds if this member overrides or implements (reflexively, transitively)
376353
* `that` member.
377354
*/
378-
predicate overridesOrImplementsOrEquals(Virtualizable that) {
355+
predicate overridesOrImplementsOrEquals(Overridable that) {
379356
this = that or
380357
this.overridesOrImplements(that)
381358
}
382359
}
383360

361+
/**
362+
* A member where the `virtual` modifier is valid. That is, a method,
363+
* a property, an indexer, or an event.
364+
*
365+
* Equivalently, these are the members that can be defined in an interface.
366+
*
367+
* Unlike `Overridable`, this class excludes accessors.
368+
*/
369+
class Virtualizable extends Overridable, Member, @virtualizable {
370+
/** Holds if this member has the modifier `override`. */
371+
predicate isOverride() { this.hasModifier("override") }
372+
373+
/** Holds if this member is `virtual`. */
374+
predicate isVirtual() { this.hasModifier("virtual") }
375+
376+
override predicate isPublic() {
377+
Member.super.isPublic() or
378+
this.implementsExplicitInterface()
379+
}
380+
381+
override predicate isPrivate() {
382+
super.isPrivate() and
383+
not this.implementsExplicitInterface()
384+
}
385+
386+
override predicate isOverridableOrImplementable() {
387+
not this.isSealed() and
388+
not this.getDeclaringType().isSealed() and
389+
(
390+
this.isVirtual() or
391+
this.isOverride() or
392+
this.isAbstract() or
393+
this.getDeclaringType() instanceof Interface
394+
)
395+
}
396+
}
397+
384398
/**
385399
* A parameterizable declaration. Either a callable (`Callable`), a delegate
386400
* type (`DelegateType`), or an indexer (`Indexer`).

csharp/ql/lib/semmle/code/csharp/Property.qll

+5-1
Original file line numberDiff line numberDiff line change
@@ -315,7 +315,7 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer
315315
* An accessor. Either a getter (`Getter`), a setter (`Setter`), or event
316316
* accessor (`EventAccessor`).
317317
*/
318-
class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
318+
class Accessor extends Callable, Modifiable, Attributable, Overridable, @callable_accessor {
319319
override ValueOrRefType getDeclaringType() { result = this.getDeclaration().getDeclaringType() }
320320

321321
/** Gets the assembly name of this accessor. */
@@ -376,6 +376,10 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
376376
not (result instanceof AccessModifier and exists(this.getAnAccessModifier()))
377377
}
378378

379+
override predicate isOverridableOrImplementable() {
380+
this.getDeclaration().isOverridableOrImplementable()
381+
}
382+
379383
override Accessor getUnboundDeclaration() { accessors(this, _, _, _, result) }
380384

381385
override Location getALocation() { accessor_location(this, result) }

csharp/ql/lib/semmle/code/csharp/controlflow/Guards.qll

+1-1
Original file line numberDiff line numberDiff line change
@@ -1086,7 +1086,7 @@ module Internal {
10861086
*/
10871087
private Callable customNullCheck(Parameter p, BooleanValue retVal, boolean isNull) {
10881088
result.getReturnType() instanceof BoolType and
1089-
not result.(Virtualizable).isOverridableOrImplementable() and
1089+
not result.(Overridable).isOverridableOrImplementable() and
10901090
p.getCallable() = result and
10911091
not p.isParams() and
10921092
p.getType() = any(Type t | t instanceof RefType or t instanceof NullableType) and

csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll

+1-5
Original file line numberDiff line numberDiff line change
@@ -361,11 +361,7 @@ private class UnboundCallable extends Callable {
361361

362362
predicate overridesOrImplementsUnbound(UnboundCallable that) {
363363
exists(Callable c |
364-
this.(Virtualizable).overridesOrImplementsOrEquals(c) or
365-
this = c.(OverridableCallable).getAnUltimateImplementor() or
366-
this = c.(OverridableCallable).getAnOverrider+()
367-
|
368-
this != c and
364+
this.(OverridableCallable).overridesOrImplements(c) and
369365
that = c.getUnboundDeclaration()
370366
)
371367
}

0 commit comments

Comments
 (0)