Files
codeql/csharp/ql/test/query-tests/Language Abuse/UselessUpcast/UselessUpcast.cs
2021-07-01 16:09:11 +02:00

166 lines
3.3 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using static StaticMethods;
interface I1 { int Foo(); }
interface I2 { float Foo(); }
interface I3 : I2 { }
interface I4 : I3 { }
class A : I1, I2
{
public int Foo() { return 0; }
float I2.Foo() { return 0; }
public void M(A a) { }
}
class B : A
{
public static bool operator==(B b1, B b2) { return false; }
public static bool operator!=(B b1, B b2) { return true; }
public void M(B b) { }
}
class C : B { }
class D : C { }
static class AExtensions1
{
public static void M1(this A a, A x) { }
public static void M2(this A a, A x) { }
}
static class AExtensions2
{
public static void M2(this A a, B b) { }
}
class Tests
{
void Fn(A a) { }
void Fn(B a) { }
void Fn2(A a) { }
void Test1(string[] args)
{
A a = new A();
B b = new B();
object o;
o = (A)b; // BAD
o = (B)b; // GOOD: Not an upcast
b.M((A)b); // GOOD: Disambiguating method call
a.M1((A)b); // BAD
a.M2((A)b); // GOOD: Disambiguating method call
o = true ? (A)a : b; // GOOD: Needed for ternary
o = a ?? (A)b; // GOOD: Null coalescing expression
Fn((A)b); // GOOD: Disambiguating method call
Fn2((A)b); // BAD
((I2)a).Foo(); // GOOD: Cast to an interface
o = a==(A)b; // GOOD: EQExpr
o = b==(B)b; // GOOD: Operator call
var act = (Action) (() => { }); // GOOD
var objects = args.Select(arg => (object)arg); // GOOD
M1((A)b); // GOOD: disambiguate targets from `StaticMethods`
StaticMethods.M1((A)b); // GOOD: disambiguate targets from `StaticMethods`
void M2(A _) { }
M2((A)b); // BAD: local functions cannot be overloaded
}
static void M2(A _) { }
void Test2(B b)
{
// BAD: even though `StaticMethods` has an `M2`, only overloads in
// `Tests` are taken into account
M2((A)b);
}
class Nested
{
static void M2(B _) { }
static void Test(C c)
{
// BAD: even though `StaticMethods` and `Tests` have `M2`s, only
// overloads in `Nested` are taken into account
M2((B)c);
}
}
}
static class IExtensions
{
public static void M1(this I2 i) { }
public static void M1(this I3 i) =>
M1((I2)i); // GOOD
public static void M1(I4 i)
{
M1((I3)i); // GOOD
((I3)i).M1(); // GOOD
}
public static void M2(I2 i) { }
public static void M2(this I3 i) =>
M2((I2)i); // GOOD
}
static class StaticMethods
{
public static void M1(A _) { }
public static void M1(B _) { }
public static void M2(B _) { }
}
class Constructors : I2
{
Constructors(I1 i) { }
Constructors(I2 i) { }
Constructors(Constructors c) : this((I1)c) { } // GOOD
Constructors(Sub s) : this((I2)s) { } // GOOD
void M(Constructors c)
{
new Constructors((I1)c); // GOOD
new Constructors((I2)c); // GOOD
}
public int Foo() => 0;
float I2.Foo() => 0;
class Sub : Constructors
{
public Sub(Sub s) : base((I1)s) { } // GOOD
}
class SubSub : Sub
{
SubSub(SubSub ss) : base((Sub)ss) { } // BAD
void M(SubSub ss)
{
new Sub((Sub)ss); // BAD
}
}
}