C#: Introduce class Overridable

The class `Overridable` generalizes the existing class `Virtualizable` by also
including accessors. This allows for quite a bit of code to be simplified.
This commit is contained in:
Tom Hvitved
2021-12-13 20:07:54 +01:00
parent 1c79d1f985
commit a9c438924e
15 changed files with 103 additions and 205 deletions

View File

@@ -205,7 +205,7 @@ private class RefArg extends AssignableAccess {
*/
predicate isAnalyzable(Parameter p) {
exists(Callable callable | callable = this.getUnboundDeclarationTarget(p) |
not callable.(Virtualizable).isOverridableOrImplementable() and
not callable.(Overridable).isOverridableOrImplementable() and
callable.hasBody()
)
}

View File

@@ -4,7 +4,7 @@
* Provides logic for determining interface member implementations.
*
* Do not use the predicates in this library directly; use the methods
* of the class `Virtualizable` instead.
* of the class `Overridable` instead.
*/
import csharp
@@ -35,7 +35,7 @@ private import Conversion
* `implements(A.M, I.M, B)` and `implements(C.M, I.M, C)`.
*/
cached
predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
predicate implements(Overridable m1, Overridable m2, ValueOrRefType t) {
exists(Interface i |
i = m2.getDeclaringType() and
t.getABaseInterface+() = i and
@@ -66,7 +66,7 @@ predicate implements(Virtualizable m1, Virtualizable m2, ValueOrRefType t) {
* for type `C`, because `C.M()` conflicts.
*/
pragma[nomagic]
private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m, ValueOrRefType t) {
private Overridable getAnImplementedInterfaceMemberForSubType(Overridable m, ValueOrRefType t) {
result = getACompatibleInterfaceMember(m) and
t = m.getDeclaringType()
or
@@ -78,7 +78,7 @@ private Virtualizable getAnImplementedInterfaceMemberForSubType(Virtualizable m,
}
pragma[noinline]
private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Virtualizable m) {
private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Overridable m) {
m = getACompatibleInterfaceMember(t.getAMember())
}
@@ -88,7 +88,7 @@ private predicate hasMemberCompatibleWithInterfaceMember(ValueOrRefType t, Virtu
* the interface member is accessed.
*/
pragma[nomagic]
private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
private Overridable getACompatibleInterfaceMember(Overridable m) {
result = getACompatibleInterfaceMemberAux(m) and
(
// If there is both an implicit and an explicit compatible member
@@ -100,14 +100,14 @@ private Virtualizable getACompatibleInterfaceMember(Virtualizable m) {
}
pragma[nomagic]
private Virtualizable getACompatibleExplicitInterfaceMember(Virtualizable m, ValueOrRefType declType) {
private Overridable getACompatibleExplicitInterfaceMember(Overridable m, ValueOrRefType declType) {
result = getACompatibleInterfaceMemberAux(m) and
declType = m.getDeclaringType() and
m.implementsExplicitInterface()
}
pragma[nomagic]
private Virtualizable getACompatibleInterfaceMemberAux(Virtualizable m) {
private Overridable getACompatibleInterfaceMemberAux(Overridable m) {
result = getACompatibleInterfaceAccessor(m) or
result = getACompatibleInterfaceIndexer(m) or
result = getACompatibleInterfaceMethod(m)

View File

@@ -180,29 +180,15 @@ class Member extends DotNet::Member, Modifiable, @member {
override predicate isStatic() { Modifiable.super.isStatic() }
}
private class TOverridable = @virtualizable or @callable_accessor;
/**
* A member where the `virtual` modifier is valid. That is, a method,
* a property, an indexer, or an event.
* A declaration that can be overridden or implemented. That is, a method,
* a property, an indexer, an event, or an accessor.
*
* Equivalently, these are the members that can be defined in an interface.
* Unlike `Virtualizable`, this class includes accessors.
*/
class Virtualizable extends Member, @virtualizable {
/** Holds if this member has the modifier `override`. */
predicate isOverride() { this.hasModifier("override") }
/** Holds if this member is `virtual`. */
predicate isVirtual() { this.hasModifier("virtual") }
override predicate isPublic() {
Member.super.isPublic() or
this.implementsExplicitInterface()
}
override predicate isPrivate() {
super.isPrivate() and
not this.implementsExplicitInterface()
}
class Overridable extends Declaration, TOverridable {
/**
* Gets any interface this member explicitly implements; this only applies
* to members that can be declared on an interface, i.e. methods, properties,
@@ -216,19 +202,10 @@ class Virtualizable extends Member, @virtualizable {
predicate implementsExplicitInterface() { exists(this.getExplicitlyImplementedInterface()) }
/** Holds if this member can be overridden or implemented. */
predicate isOverridableOrImplementable() {
not this.isSealed() and
not this.getDeclaringType().isSealed() and
(
this.isVirtual() or
this.isOverride() or
this.isAbstract() or
this.getDeclaringType() instanceof Interface
)
}
predicate isOverridableOrImplementable() { none() }
/** Gets the member that is immediately overridden by this member, if any. */
Virtualizable getOverridee() {
Overridable getOverridee() {
overrides(this, result)
or
// For accessors (which are `Callable`s), the extractor generates entries
@@ -242,7 +219,7 @@ class Virtualizable extends Member, @virtualizable {
}
/** Gets a member that immediately overrides this member, if any. */
Virtualizable getAnOverrider() { this = result.getOverridee() }
Overridable getAnOverrider() { this = result.getOverridee() }
/** Holds if this member is overridden by some other member. */
predicate isOverridden() { exists(this.getAnOverrider()) }
@@ -273,10 +250,10 @@ class Virtualizable extends Member, @virtualizable {
* `A.M.getImplementee(B) = I.M` and
* `C.M.getImplementee(C) = I.M`.
*/
Virtualizable getImplementee(ValueOrRefType t) { implements(this, result, t) }
Overridable getImplementee(ValueOrRefType t) { implements(this, result, t) }
/** Gets the interface member that is immediately implemented by this member, if any. */
Virtualizable getImplementee() { result = this.getImplementee(_) }
Overridable getImplementee() { result = this.getImplementee(_) }
/**
* Gets a member that immediately implements this interface member, if any.
@@ -301,10 +278,10 @@ class Virtualizable extends Member, @virtualizable {
* `I.M.getAnImplementor(B) = A.M` and
* `I.M.getAnImplementor(C) = C.M`.
*/
Virtualizable getAnImplementor(ValueOrRefType t) { this = result.getImplementee(t) }
Overridable getAnImplementor(ValueOrRefType t) { this = result.getImplementee(t) }
/** Gets a member that immediately implements this interface member, if any. */
Virtualizable getAnImplementor() { this = result.getImplementee() }
Overridable getAnImplementor() { this = result.getImplementee() }
/**
* Gets an interface member that is (transitively) implemented by this
@@ -334,8 +311,8 @@ class Virtualizable extends Member, @virtualizable {
* - If this member is `D.M` then `I.M = getAnUltimateImplementee()`.
*/
pragma[nomagic]
Virtualizable getAnUltimateImplementee() {
exists(Virtualizable implementation, ValueOrRefType implementationType |
Overridable getAnUltimateImplementee() {
exists(Overridable implementation, ValueOrRefType implementationType |
implements(implementation, result, implementationType)
|
this = implementation
@@ -354,7 +331,7 @@ class Virtualizable extends Member, @virtualizable {
* Note that this is generally *not* equivalent with
* `getImplementor().getAnOverrider*()` (see `getImplementee`).
*/
Virtualizable getAnUltimateImplementor() { this = result.getAnUltimateImplementee() }
Overridable getAnUltimateImplementor() { this = result.getAnUltimateImplementee() }
/** Holds if this interface member is implemented by some other member. */
predicate isImplemented() { exists(this.getAnImplementor()) }
@@ -366,7 +343,7 @@ class Virtualizable extends Member, @virtualizable {
* Holds if this member overrides or implements (transitively)
* `that` member.
*/
predicate overridesOrImplements(Virtualizable that) {
predicate overridesOrImplements(Overridable that) {
this.getOverridee+() = that or
this.getAnUltimateImplementee() = that
}
@@ -375,12 +352,49 @@ class Virtualizable extends Member, @virtualizable {
* Holds if this member overrides or implements (reflexively, transitively)
* `that` member.
*/
predicate overridesOrImplementsOrEquals(Virtualizable that) {
predicate overridesOrImplementsOrEquals(Overridable that) {
this = that or
this.overridesOrImplements(that)
}
}
/**
* A member where the `virtual` modifier is valid. That is, a method,
* a property, an indexer, or an event.
*
* Equivalently, these are the members that can be defined in an interface.
*
* Unlike `Overridable`, this class excludes accessors.
*/
class Virtualizable extends Overridable, Member, @virtualizable {
/** Holds if this member has the modifier `override`. */
predicate isOverride() { this.hasModifier("override") }
/** Holds if this member is `virtual`. */
predicate isVirtual() { this.hasModifier("virtual") }
override predicate isPublic() {
Member.super.isPublic() or
this.implementsExplicitInterface()
}
override predicate isPrivate() {
super.isPrivate() and
not this.implementsExplicitInterface()
}
override predicate isOverridableOrImplementable() {
not this.isSealed() and
not this.getDeclaringType().isSealed() and
(
this.isVirtual() or
this.isOverride() or
this.isAbstract() or
this.getDeclaringType() instanceof Interface
)
}
}
/**
* A parameterizable declaration. Either a callable (`Callable`), a delegate
* type (`DelegateType`), or an indexer (`Indexer`).

View File

@@ -315,7 +315,7 @@ class Indexer extends DeclarationWithGetSetAccessors, Parameterizable, @indexer
* An accessor. Either a getter (`Getter`), a setter (`Setter`), or event
* accessor (`EventAccessor`).
*/
class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
class Accessor extends Callable, Modifiable, Attributable, Overridable, @callable_accessor {
override ValueOrRefType getDeclaringType() { result = this.getDeclaration().getDeclaringType() }
/** Gets the assembly name of this accessor. */
@@ -376,6 +376,10 @@ class Accessor extends Callable, Modifiable, Attributable, @callable_accessor {
not (result instanceof AccessModifier and exists(this.getAnAccessModifier()))
}
override predicate isOverridableOrImplementable() {
this.getDeclaration().isOverridableOrImplementable()
}
override Accessor getUnboundDeclaration() { accessors(this, _, _, _, result) }
override Location getALocation() { accessor_location(this, result) }

View File

@@ -1086,7 +1086,7 @@ module Internal {
*/
private Callable customNullCheck(Parameter p, BooleanValue retVal, boolean isNull) {
result.getReturnType() instanceof BoolType and
not result.(Virtualizable).isOverridableOrImplementable() and
not result.(Overridable).isOverridableOrImplementable() and
p.getCallable() = result and
not p.isParams() and
p.getType() = any(Type t | t instanceof RefType or t instanceof NullableType) and

View File

@@ -360,11 +360,7 @@ private class UnboundCallable extends Callable {
predicate overridesOrImplementsUnbound(UnboundCallable that) {
exists(Callable c |
this.(Virtualizable).overridesOrImplementsOrEquals(c) or
this = c.(OverridableCallable).getAnUltimateImplementor() or
this = c.(OverridableCallable).getAnOverrider+()
|
this != c and
this.(OverridableCallable).overridesOrImplements(c) and
that = c.getUnboundDeclaration()
)
}

View File

@@ -8,24 +8,11 @@ import csharp
/**
* A callable that can be overridden or implemented.
*
* Unlike the class `Virtualizable`, this class only includes methods that
* can actually be overriden/implemented. Additionally, this class includes
* accessors whose declarations can actually be overridden/implemented.
* Unlike the class `Overridable`, this class only includes callables that
* can actually be overriden/implemented.
*/
class OverridableCallable extends Callable {
OverridableCallable() {
this.(Method).isOverridableOrImplementable() or
this.(Accessor).getDeclaration().isOverridableOrImplementable()
}
/** Gets a callable that immediately overrides this callable, if any. */
Callable getAnOverrider() { none() }
/**
* Gets a callable that immediately implements this interface callable,
* if any.
*/
Callable getAnImplementor(ValueOrRefType t) { none() }
class OverridableCallable extends Callable, Overridable {
OverridableCallable() { this.isOverridableOrImplementable() }
/**
* Gets a callable that immediately implements this interface member,
@@ -68,40 +55,6 @@ class OverridableCallable extends Callable {
)
}
/**
* Gets a callable that (transitively) implements this interface callable,
* if any. That is, either this interface callable is immediately implemented
* by the result, or the result overrides (transitively) another callable that
* immediately implements this interface callable.
*
* Note that this is generally *not* equivalent with
*
* ```ql
* result = getAnImplementor()
* or
* result = getAnImplementor().(OverridableCallable).getAnOverrider+()`
* ```
*
* as the example below illustrates:
*
* ```csharp
* interface I { void M(); }
*
* class A { public virtual void M() { } }
*
* class B : A, I { }
*
* class C : A { public override void M() }
*
* class D : B { public override void M() }
* ```
*
* If this callable is `I.M` then `A.M = getAnUltimateImplementor() ` and
* `D.M = getAnUltimateImplementor()`. However, it is *not* the case that
* `C.M = getAnUltimateImplementor()`, because `C` is not a sub type of `I`.
*/
Callable getAnUltimateImplementor() { none() }
/**
* Gets a callable that overrides (transitively) another callable that
* implements this interface callable, if any.
@@ -210,73 +163,10 @@ class OverridableCallable extends Callable {
}
/** An overridable method. */
class OverridableMethod extends Method, OverridableCallable {
override Method getAnOverrider() { result = Method.super.getAnOverrider() }
override Method getAnImplementor(ValueOrRefType t) { result = Method.super.getAnImplementor(t) }
override Method getAnUltimateImplementor() { result = Method.super.getAnUltimateImplementor() }
override Method getInherited(ValueOrRefType t) {
result = OverridableCallable.super.getInherited(t)
}
override Method getAnOverrider(ValueOrRefType t) {
result = OverridableCallable.super.getAnOverrider(t)
}
}
deprecated class OverridableMethod extends Method, OverridableCallable { }
/** An overridable accessor. */
class OverridableAccessor extends Accessor, OverridableCallable {
override Accessor getAnOverrider() { overrides(result, this) }
override Accessor getAnImplementor(ValueOrRefType t) {
exists(Virtualizable implementor, int kind |
this.getAnImplementorAux(t, implementor, kind) and
result.getDeclaration() = implementor and
getAccessorKind(result) = kind
)
}
// predicate folding to get proper join order
private predicate getAnImplementorAux(ValueOrRefType t, Virtualizable implementor, int kind) {
exists(Virtualizable implementee |
implementee = this.getDeclaration() and
kind = getAccessorKind(this) and
implementor = implementee.getAnImplementor(t)
)
}
override Accessor getAnUltimateImplementor() {
exists(Virtualizable implementor, int kind |
this.getAnUltimateImplementorAux(implementor, kind) and
result.getDeclaration() = implementor and
getAccessorKind(result) = kind
)
}
// predicate folding to get proper join order
private predicate getAnUltimateImplementorAux(Virtualizable implementor, int kind) {
exists(Virtualizable implementee |
implementee = this.getDeclaration() and
kind = getAccessorKind(this) and
implementor = implementee.getAnUltimateImplementor()
)
}
override Accessor getInherited(ValueOrRefType t) {
result = OverridableCallable.super.getInherited(t)
}
override Accessor getAnOverrider(ValueOrRefType t) {
result = OverridableCallable.super.getAnOverrider(t)
}
}
private int getAccessorKind(Accessor a) {
accessors(a, result, _, _, _) or
event_accessors(a, -result, _, _, _)
}
deprecated class OverridableAccessor extends Accessor, OverridableCallable { }
/** An unbound type. */
class UnboundDeclarationType extends Type {

View File

@@ -996,7 +996,7 @@ class QualifiableExpr extends Expr, @qualifiable_expr {
*/
predicate targetIsOverridableOrImplementable() {
not this.getQualifier() instanceof BaseAccess and
this.getQualifiedDeclaration().(Virtualizable).isOverridableOrImplementable()
this.getQualifiedDeclaration().(Overridable).isOverridableOrImplementable()
}
/** Holds if this expression has a conditional qualifier `?.` */

View File

@@ -54,7 +54,7 @@ class ExternalAPIDataNode extends DataFlow::Node {
// Defined outside the source archive
not call.getTarget().fromSource() and
// Not a call to a method which is overridden in source
not exists(Virtualizable m |
not exists(Overridable m |
m.overridesOrImplementsOrEquals(call.getTarget().getUnboundDeclaration()) and
m.fromSource()
) and

View File

@@ -155,4 +155,4 @@ int getFieldBitOffset(Field f) {
/**
* Holds if the specified `Function` can be overridden in a derived class.
*/
predicate isFunctionVirtual(Function f) { f.(CSharp::Virtualizable).isOverridableOrImplementable() }
predicate isFunctionVirtual(Function f) { f.(CSharp::Overridable).isOverridableOrImplementable() }

View File

@@ -19,7 +19,7 @@ query predicate withTarget(WithExpr with, RecordCloneMethod clone, Constructor c
query predicate cloneOverrides(string b, string o) {
exists(RecordCloneMethod base, RecordCloneMethod overrider |
base.getDeclaringType().fromSource() and
base.(Virtualizable).getAnOverrider() = overrider and
base.getAnOverrider() = overrider and
b = getSignature(base) and
o = getSignature(overrider)
)

View File

@@ -187,12 +187,6 @@ edges
| CollectionFlow.cs:373:52:373:53 | access to parameter ts [element] : A | CollectionFlow.cs:373:52:373:56 | access to array element |
| CollectionFlow.cs:373:52:373:53 | access to parameter ts [element] : A | CollectionFlow.cs:373:52:373:56 | access to array element |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | CollectionFlow.cs:375:63:375:69 | access to indexer |
| CollectionFlow.cs:377:61:377:64 | dict [element, property Value] : A | CollectionFlow.cs:377:75:377:78 | access to parameter dict [element, property Value] : A |
| CollectionFlow.cs:377:75:377:78 | access to parameter dict [element, property Value] : A | CollectionFlow.cs:377:75:377:81 | access to indexer |
@@ -204,12 +198,6 @@ edges
| CollectionFlow.cs:381:41:381:42 | access to parameter ts [element] : A | CollectionFlow.cs:381:41:381:45 | access to array element : A |
| CollectionFlow.cs:381:41:381:42 | access to parameter ts [element] : A | CollectionFlow.cs:381:41:381:45 | access to array element : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | CollectionFlow.cs:383:52:383:58 | access to indexer : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | CollectionFlow.cs:383:52:383:58 | access to indexer : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | CollectionFlow.cs:383:52:383:58 | access to indexer : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | CollectionFlow.cs:383:52:383:58 | access to indexer : A |
| CollectionFlow.cs:385:58:385:61 | dict [element, property Value] : A | CollectionFlow.cs:385:67:385:70 | access to parameter dict [element, property Value] : A |
| CollectionFlow.cs:385:67:385:70 | access to parameter dict [element, property Value] : A | CollectionFlow.cs:385:67:385:73 | access to indexer : A |
@@ -402,12 +390,6 @@ nodes
| CollectionFlow.cs:373:52:373:53 | access to parameter ts [element] : A | semmle.label | access to parameter ts [element] : A |
| CollectionFlow.cs:373:52:373:56 | access to array element | semmle.label | access to array element |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:375:49:375:52 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:375:63:375:66 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:375:63:375:69 | access to indexer | semmle.label | access to indexer |
| CollectionFlow.cs:377:61:377:64 | dict [element, property Value] : A | semmle.label | dict [element, property Value] : A |
@@ -424,16 +406,7 @@ nodes
| CollectionFlow.cs:381:41:381:45 | access to array element : A | semmle.label | access to array element : A |
| CollectionFlow.cs:381:41:381:45 | access to array element : A | semmle.label | access to array element : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:383:43:383:46 | list [element] : A | semmle.label | list [element] : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:383:52:383:55 | access to parameter list [element] : A | semmle.label | access to parameter list [element] : A |
| CollectionFlow.cs:383:52:383:58 | access to indexer : A | semmle.label | access to indexer : A |
| CollectionFlow.cs:383:52:383:58 | access to indexer : A | semmle.label | access to indexer : A |
| CollectionFlow.cs:383:52:383:58 | access to indexer : A | semmle.label | access to indexer : A |
| CollectionFlow.cs:383:52:383:58 | access to indexer : A | semmle.label | access to indexer : A |
| CollectionFlow.cs:385:58:385:61 | dict [element, property Value] : A | semmle.label | dict [element, property Value] : A |
| CollectionFlow.cs:385:67:385:70 | access to parameter dict [element, property Value] : A | semmle.label | access to parameter dict [element, property Value] : A |

View File

@@ -1,6 +1,6 @@
import csharp
from Virtualizable v1, Virtualizable v2
from Overridable v1, Overridable v2
where
v1 = v2.getAnUltimateImplementor() and
v1.fromSource() and

View File

@@ -16,23 +16,44 @@
| overrides.A8.Item[int] | overrides.A1.Item[int] | overrides |
| overrides.A8.M<T>(dynamic[], T) | overrides.A1.M<T>(dynamic[], T) | overrides |
| overrides.A8.Property | overrides.A1.Property | overrides |
| overrides.A8.add_Event(EventHandler) | overrides.A1.add_Event(EventHandler) | overrides |
| overrides.A8.get_Item(int) | overrides.A1.get_Item(int) | overrides |
| overrides.A8.get_Property() | overrides.A1.get_Property() | overrides |
| overrides.A8.remove_Event(EventHandler) | overrides.A1.remove_Event(EventHandler) | overrides |
| overrides.A8.set_Property(int) | overrides.A1.set_Property(int) | overrides |
| overrides.A9.Event | overrides.A1.Event | overrides |
| overrides.A9.Item[int] | overrides.A1.Item[int] | overrides |
| overrides.A9.M<T>(dynamic[], T) | overrides.A1.M<T>(dynamic[], T) | overrides |
| overrides.A9.Property | overrides.A1.Property | overrides |
| overrides.A9.add_Event(EventHandler) | overrides.A1.add_Event(EventHandler) | overrides |
| overrides.A9.get_Item(int) | overrides.A1.get_Item(int) | overrides |
| overrides.A9.get_Property() | overrides.A1.get_Property() | overrides |
| overrides.A9.remove_Event(EventHandler) | overrides.A1.remove_Event(EventHandler) | overrides |
| overrides.A9.set_Property(int) | overrides.A1.set_Property(int) | overrides |
| overrides.A.E1 | overrides.B.E1 | overrides |
| overrides.A.P1 | overrides.B.P1 | overrides |
| overrides.A.P2 | overrides.B.P2 | overrides |
| overrides.A.P3 | overrides.B.P3 | overrides |
| overrides.A.P4 | overrides.C.P4 | overrides |
| overrides.A.add_E1(EventHandler) | overrides.B.add_E1(EventHandler) | overrides |
| overrides.A.f2() | overrides.B.f2() | overrides |
| overrides.A.f3() | overrides.B.f3() | overrides |
| overrides.A.f4() | overrides.C.f4() | overrides |
| overrides.A.f5() | overrides.B.f5() | overrides |
| overrides.A.f6() | overrides.B.f6() | overrides |
| overrides.A.get_P1() | overrides.B.get_P1() | overrides |
| overrides.A.get_P2() | overrides.B.get_P2() | overrides |
| overrides.A.get_P3() | overrides.B.get_P3() | overrides |
| overrides.A.get_P4() | overrides.C.get_P4() | overrides |
| overrides.A.remove_E1(EventHandler) | overrides.B.remove_E1(EventHandler) | overrides |
| overrides.A.set_P1(string) | overrides.B.set_P1(string) | overrides |
| overrides.A.set_P3(string) | overrides.B.set_P3(string) | overrides |
| overrides.A.set_P4(string) | overrides.C.set_P4(string) | overrides |
| overrides.B.f5() | overrides.C.f5() | overrides |
| overrides.C2.Prop | overrides.C1.Prop | overrides |
| overrides.C2.Prop | overrides.I3.Prop | implements |
| overrides.C2.get_Prop() | overrides.C1.get_Prop() | overrides |
| overrides.C2.set_Prop(string) | overrides.C1.set_Prop(string) | overrides |
| overrides.C3<>.Item[int] | overrides.I4.MyIndexer[int] | implements |
| overrides.C3<>.Method() | overrides.I4.Method() | implements |
| overrides.C3<>.Prop | overrides.I3.Prop | implements |

View File

@@ -1,6 +1,6 @@
import csharp
from Virtualizable v1, Virtualizable v2, string kind
from Overridable v1, Overridable v2, string kind
where
(
v1.getOverridee() = v2 and kind = "overrides"