@@ -820,6 +820,7 @@ module ControlFlow {
820820 */
821821 private module Successor {
822822 private import semmle.code.csharp.ExprOrStmtParent
823+ private import semmle.code.csharp.controlflow.internal.NonReturning
823824
824825 /**
825826 * A control flow element where the children are evaluated following a
@@ -1730,145 +1731,6 @@ module ControlFlow {
17301731 )
17311732 }
17321733
1733- /**
1734- * Provides a simple analysis for identifying calls to callables that will
1735- * not return.
1736- */
1737- private module NonReturning {
1738- private import semmle.code.csharp.ExprOrStmtParent
1739- private import semmle.code.csharp.commons.Assertions
1740- private import semmle.code.csharp.frameworks.System
1741-
1742- /** A call that definitely does not return (conservative analysis). */
1743- abstract class NonReturningCall extends Call {
1744- /** Gets a valid completion for this non-returning call. */
1745- abstract Completion getACompletion ( ) ;
1746- }
1747-
1748- private class ExitingCall extends NonReturningCall {
1749- ExitingCall ( ) {
1750- this .getTarget ( ) instanceof ExitingCallable
1751- or
1752- exists ( AssertMethod m | m = this .( FailingAssertion ) .getAssertMethod ( ) |
1753- not exists ( m .getExceptionClass ( ) )
1754- )
1755- }
1756-
1757- override ExitCompletion getACompletion ( ) { any ( ) }
1758- }
1759-
1760- private class ThrowingCall extends NonReturningCall {
1761- private ThrowCompletion c ;
1762-
1763- ThrowingCall ( ) {
1764- c = this .getTarget ( ) .( ThrowingCallable ) .getACallCompletion ( )
1765- or
1766- exists ( AssertMethod m | m = this .( FailingAssertion ) .getAssertMethod ( ) |
1767- c .getExceptionClass ( ) = m .getExceptionClass ( )
1768- )
1769- }
1770-
1771- override ThrowCompletion getACompletion ( ) { result = c }
1772- }
1773-
1774- abstract private class NonReturningCallable extends Callable {
1775- NonReturningCallable ( ) {
1776- not exists ( ReturnStmt ret | ret .getEnclosingCallable ( ) = this ) and
1777- not hasAccessorAutoImplementation ( this , _) and
1778- not exists ( Virtualizable v | v .isOverridableOrImplementable ( ) |
1779- v = this or
1780- v = this .( Accessor ) .getDeclaration ( )
1781- )
1782- }
1783- }
1784-
1785- abstract private class ExitingCallable extends NonReturningCallable { }
1786-
1787- private class DirectlyExitingCallable extends ExitingCallable {
1788- DirectlyExitingCallable ( ) {
1789- this = any ( Method m |
1790- m .hasQualifiedName ( "System.Environment" , "Exit" ) or
1791- m .hasQualifiedName ( "System.Windows.Forms.Application" , "Exit" )
1792- )
1793- }
1794- }
1795-
1796- private class IndirectlyExitingCallable extends ExitingCallable {
1797- IndirectlyExitingCallable ( ) {
1798- forex ( ControlFlowElement body | body = this .getABody ( ) | body = getAnExitingElement ( ) )
1799- }
1800- }
1801-
1802- private ControlFlowElement getAnExitingElement ( ) {
1803- result instanceof ExitingCall
1804- or
1805- result = getAnExitingStmt ( )
1806- }
1807-
1808- private Stmt getAnExitingStmt ( ) {
1809- result .( ExprStmt ) .getExpr ( ) = getAnExitingElement ( )
1810- or
1811- result .( BlockStmt ) .getFirstStmt ( ) = getAnExitingElement ( )
1812- or
1813- exists ( IfStmt ifStmt |
1814- result = ifStmt and
1815- ifStmt .getThen ( ) = getAnExitingElement ( ) and
1816- ifStmt .getElse ( ) = getAnExitingElement ( )
1817- )
1818- }
1819-
1820- private class ThrowingCallable extends NonReturningCallable {
1821- ThrowingCallable ( ) {
1822- forex ( ControlFlowElement body | body = this .getABody ( ) | body = getAThrowingElement ( _) )
1823- }
1824-
1825- /** Gets a valid completion for a call to this throwing callable. */
1826- ThrowCompletion getACallCompletion ( ) { this .getABody ( ) = getAThrowingElement ( result ) }
1827- }
1828-
1829- private predicate directlyThrows ( ThrowElement te , ThrowCompletion c ) {
1830- c .getExceptionClass ( ) = te .getThrownExceptionType ( ) and
1831- // For stub implementations, there may exist proper implementations that are not seen
1832- // during compilation, so we conservatively rule those out
1833- not isStub ( te )
1834- }
1835-
1836- private ControlFlowElement getAThrowingElement ( ThrowCompletion c ) {
1837- c = result .( ThrowingCall ) .getACompletion ( )
1838- or
1839- directlyThrows ( result , c )
1840- or
1841- result = getAThrowingStmt ( c )
1842- }
1843-
1844- private Stmt getAThrowingStmt ( ThrowCompletion c ) {
1845- directlyThrows ( result , c )
1846- or
1847- result .( ExprStmt ) .getExpr ( ) = getAThrowingElement ( c )
1848- or
1849- result .( BlockStmt ) .getFirstStmt ( ) = getAThrowingStmt ( c )
1850- or
1851- exists ( IfStmt ifStmt , ThrowCompletion c1 , ThrowCompletion c2 |
1852- result = ifStmt and
1853- ifStmt .getThen ( ) = getAThrowingStmt ( c1 ) and
1854- ifStmt .getElse ( ) = getAThrowingStmt ( c2 )
1855- |
1856- c = c1
1857- or
1858- c = c2
1859- )
1860- }
1861-
1862- /** Holds if `throw` element `te` indicates a stub implementation. */
1863- private predicate isStub ( ThrowElement te ) {
1864- exists ( Expr e | e = te .getExpr ( ) |
1865- e instanceof NullLiteral or
1866- e .getType ( ) instanceof SystemNotImplementedExceptionClass
1867- )
1868- }
1869- }
1870- private import NonReturning
1871-
18721734 /**
18731735 * Gets a control flow successor for control flow element `cfe`, given that
18741736 * `cfe` finishes with completion `c`.
0 commit comments