diff --git a/infer/tests/codetoanalyze/hack/pulse/cannot_instantiate_abstract_class.hack b/infer/tests/codetoanalyze/hack/pulse/cannot_instantiate_abstract_class.hack index 945ed973f1..6eade1d505 100644 --- a/infer/tests/codetoanalyze/hack/pulse/cannot_instantiate_abstract_class.hack +++ b/infer/tests/codetoanalyze/hack/pulse/cannot_instantiate_abstract_class.hack @@ -10,6 +10,24 @@ class Main { public static function makeGeneric(classname $cls): void { new $cls(); } + + public static function passthrough(classname $cls): classname { + return $cls; + } + + public static function getConcreteClass(): classname { + return ConcreteClass1::class; + } + + public static function getAbstractClass(): classname { + return AbstractClass1::class; + } + + public static function makeGenericWithIndirection( + classname $cls, + ): void { + Main::makeGeneric($cls); + } } abstract class AbstractClass1 {} @@ -43,4 +61,41 @@ class Tests { public function initConcreteClassViaStaticOk(): void { ConcreteClass2::makeStatic(); } + + public function initAbstractClassViaGenericFunWithPassthroughBad(): void { + Main::makeGeneric(Main::passthrough(AbstractClass1::class)); + } + + public function initConcreteClassViaGenericFunWithPassthroughOk(): void { + Main::makeGeneric(Main::passthrough(ConcreteClass1::class)); + } + + public function initAbstractClassViaGenericFunWithExternalArgBad(): void { + Main::makeGeneric(Main::getAbstractClass()); + } + + public function initConcreteClassViaGenericFunWithExternalArgOk(): void { + Main::makeGeneric(Main::getConcreteClass()); + } + + public function initAbstractClassViaGenericWithIndirectionBad(): void { + Main::makeGenericWithIndirection(AbstractClass1::class); + } + + public function initConcreteClassViaGenericWithIndirectionOk(): void { + Main::makeGenericWithIndirection(ConcreteClass1::class); + } + + public function initAbstractClassWithSameUnrelatedSpecializationBad( + classname $cls, + ): void { + Main::makeGeneric(AbstractClass1::class); + } + + public function initAbstractClassWithSameUnrelatedSpecializationOk( + ): void { + $this->initAbstractClassWithSameUnrelatedSpecializationBad( + AbstractClass1::class, + ); + } } diff --git a/infer/tests/codetoanalyze/hack/pulse/issues.exp b/infer/tests/codetoanalyze/hack/pulse/issues.exp index 3ada3dc3d1..b467119af6 100644 --- a/infer/tests/codetoanalyze/hack/pulse/issues.exp +++ b/infer/tests/codetoanalyze/hack/pulse/issues.exp @@ -35,6 +35,10 @@ call_variadic.hack, CallVariadic::CallVariadic$static.callVariadicArg0InSinkBad, call_variadic.hack, CallVariadic::CallVariadic$static.FP_callVariadicArg0InSinkOk, 1, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `$root.Level1::taintSource` with kind `Simple`,when calling `Variadic::Variadic$static.variadicArg0InSink` here,flows to this sink: value passed as argument `#0` to `$root.Level1::taintSink` with kind `Simple`], source: $root.Level1::taintSource, sink: $root.Level1::taintSink, tainted expression: $root.Level1::taintSource() cannot_instantiate_abstract_class.hack, CannotInstantiateAbstractClassTests::Tests.initAbstractClassViaGenericFunBad, 2, PULSE_CANNOT_INSTANTIATE_ABSTRACT_CLASS, no_bucket, ERROR, [calling context starts here,in call to `CannotInstantiateAbstractClassTests::Main$static.makeGeneric`,abstract class CannotInstantiateAbstractClassTests::AbstractClass1 initialized here] cannot_instantiate_abstract_class.hack, CannotInstantiateAbstractClassTests::Tests.initAbstractClassViaStaticBad, 2, PULSE_CANNOT_INSTANTIATE_ABSTRACT_CLASS, no_bucket, ERROR, [calling context starts here,in call to `CannotInstantiateAbstractClassTests::AbstractClass2$static.makeStatic`,abstract class CannotInstantiateAbstractClassTests::AbstractClass2 initialized here] +cannot_instantiate_abstract_class.hack, CannotInstantiateAbstractClassTests::Tests.initAbstractClassViaGenericFunWithPassthroughBad, 2, PULSE_CANNOT_INSTANTIATE_ABSTRACT_CLASS, no_bucket, ERROR, [calling context starts here,in call to `CannotInstantiateAbstractClassTests::Main$static.makeGeneric`,abstract class CannotInstantiateAbstractClassTests::AbstractClass1 initialized here] +cannot_instantiate_abstract_class.hack, CannotInstantiateAbstractClassTests::Tests.initAbstractClassViaGenericFunWithExternalArgBad, 2, PULSE_CANNOT_INSTANTIATE_ABSTRACT_CLASS, no_bucket, ERROR, [calling context starts here,in call to `CannotInstantiateAbstractClassTests::Main$static.makeGeneric`,abstract class CannotInstantiateAbstractClassTests::AbstractClass1 initialized here] +cannot_instantiate_abstract_class.hack, CannotInstantiateAbstractClassTests::Tests.initAbstractClassViaGenericWithIndirectionBad, 2, PULSE_CANNOT_INSTANTIATE_ABSTRACT_CLASS, no_bucket, ERROR, [calling context starts here,in call to `CannotInstantiateAbstractClassTests::Main$static.makeGenericWithIndirection`,in call to `CannotInstantiateAbstractClassTests::Main$static.makeGeneric`,abstract class CannotInstantiateAbstractClassTests::AbstractClass1 initialized here] +cannot_instantiate_abstract_class.hack, CannotInstantiateAbstractClassTests::Tests.initAbstractClassWithSameUnrelatedSpecializationBad, 4, PULSE_CANNOT_INSTANTIATE_ABSTRACT_CLASS, no_bucket, ERROR, [calling context starts here,in call to `CannotInstantiateAbstractClassTests::Main$static.makeGeneric`,abstract class CannotInstantiateAbstractClassTests::AbstractClass1 initialized here] closure_in_closure.hack, ClosureInClosure::Main$static.bad1, 1, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `$root.Level1::taintSource` with kind `Simple`,when calling `ClosureInClosure::Utils$static.compute` here,when calling `ClosureInClosure::Utils$static.run1` here,when calling `Closure$ClosureInClosure::Utils::compute232.__invoke` here,when calling `ClosureInClosure::Utils$static.run2` here,when calling `Closure$ClosureInClosure::Utils::compute.__invoke` here,when calling `ClosureInClosure::B.process` here,flows to this sink: value passed as argument `#0` to `$root.Level1::taintSink` with kind `Simple`], source: $root.Level1::taintSource, sink: $root.Level1::taintSink, tainted expression: $root.Level1::taintSource() closure_in_closure.hack, ClosureInClosure::Main$static.bad2, 1, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `$root.Level1::taintSource` with kind `Simple`,when calling `ClosureInClosure::Utils$static.compute` here,when calling `ClosureInClosure::Utils$static.run1` here,when calling `Closure$ClosureInClosure::Utils::compute232.__invoke` here,when calling `ClosureInClosure::Utils$static.run2` here,when calling `Closure$ClosureInClosure::Utils::compute.__invoke` here,when calling `ClosureInClosure::B.process` here,flows to this sink: value passed as argument `#0` to `$root.Level1::taintSink` with kind `Simple`], source: $root.Level1::taintSource, sink: $root.Level1::taintSink, tainted expression: $root.Level1::taintSource() closure_in_closure.hack, ClosureInClosure::Main$static.bad3, 1, TAINT_ERROR, no_bucket, ERROR, [source of the taint here: value returned from `$root.Level1::taintSource` with kind `Simple`,when calling `ClosureInClosure::Utils$static.compute` here,when calling `ClosureInClosure::Utils$static.run1` here,when calling `Closure$ClosureInClosure::Utils::compute232.__invoke` here,when calling `ClosureInClosure::Utils$static.run2` here,when calling `Closure$ClosureInClosure::Utils::compute.__invoke` here,when calling `ClosureInClosure::B.process` here,flows to this sink: value passed as argument `#0` to `$root.Level1::taintSink` with kind `Simple`], source: $root.Level1::taintSource, sink: $root.Level1::taintSink, tainted expression: $root.Level1::taintSource()