Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4112872
AlwaysReturnPlugin.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
6 KB
Referenced Files
None
Subscribers
None
AlwaysReturnPlugin.php
View Options
<?php
declare
(
strict_types
=
1
);
use
ast\Node
;
use
Phan\Analysis\BlockExitStatusChecker
;
use
Phan\CodeBase
;
use
Phan\Language\Element\Func
;
use
Phan\Language\Element\FunctionInterface
;
use
Phan\Language\Element\Method
;
use
Phan\Language\Type\NeverType
;
use
Phan\Language\Type\NullType
;
use
Phan\Language\Type\VoidType
;
use
Phan\PluginV3
;
use
Phan\PluginV3\AnalyzeFunctionCapability
;
use
Phan\PluginV3\AnalyzeMethodCapability
;
/**
* This file checks if a function, closure or method unconditionally returns.
* If the function doesn't have a void return type,
* then this plugin will emit an issue.
*
* It hooks into two events:
*
* - analyzeMethod
* Once all methods are parsed, this method will be called
* on every method in the code base
*
* - analyzeFunction
* Once all functions have been parsed, this method will
* be called on every function in the code base.
*
* A plugin file must
*
* - Contain a class that inherits from \Phan\PluginV3
*
* - End by returning an instance of that class.
*
* It is assumed without being checked that plugins aren't
* mangling state within the passed code base or context.
*
* Note: When adding new plugins,
* add them to the corresponding section of README.md
*/
final
class
AlwaysReturnPlugin
extends
PluginV3
implements
AnalyzeFunctionCapability
,
AnalyzeMethodCapability
{
/**
* @param CodeBase $code_base
* The code base in which the method exists
*
* @param Method $method
* A method being analyzed
*
* @override
*/
public
function
analyzeMethod
(
CodeBase
$code_base
,
Method
$method
):
void
{
$stmts_list
=
self
::
getStatementListToAnalyze
(
$method
);
if
(
$stmts_list
===
null
)
{
// check for abstract methods, generators, etc.
return
;
}
if
(
$method
->
getFQSEN
()
!==
$method
->
getDefiningFQSEN
())
{
// Check if this was inherited by a descendant class.
return
;
}
if
(
self
::
returnTypeOfFunctionLikeAllowsNull
(
$method
))
{
// This has at least one return statement with an expression
if
(!
BlockExitStatusChecker
::
willUnconditionallyThrowOrReturn
(
$stmts_list
))
{
if
(
$method
->
getUnionType
()->
isEmpty
()
&&
$method
->
hasReturn
())
{
if
(!
$method
->
checkHasSuppressIssueAndIncrementCount
(
'PhanPluginInconsistentReturnMethod'
))
{
self
::
emitIssue
(
$code_base
,
$method
->
getContext
(),
'PhanPluginInconsistentReturnMethod'
,
"Method {METHOD} has no return type and will inconsistently return or not return"
,
[(
string
)
$method
->
getFQSEN
()]
);
}
}
}
return
;
}
if
(!
BlockExitStatusChecker
::
willUnconditionallyThrowOrReturn
(
$stmts_list
))
{
if
(!
$method
->
checkHasSuppressIssueAndIncrementCount
(
'PhanPluginAlwaysReturnMethod'
))
{
self
::
emitIssue
(
$code_base
,
$method
->
getContext
(),
'PhanPluginAlwaysReturnMethod'
,
"Method {METHOD} has a return type of {TYPE}, but may fail to return a value"
,
[(
string
)
$method
->
getFQSEN
(),
(
string
)
$method
->
getUnionType
()]
);
}
}
}
/**
* @param CodeBase $code_base
* The code base in which the function exists
*
* @param Func $function
* A function or closure being analyzed
*
* @override
*/
public
function
analyzeFunction
(
CodeBase
$code_base
,
Func
$function
):
void
{
$stmts_list
=
self
::
getStatementListToAnalyze
(
$function
);
if
(
$stmts_list
===
null
)
{
// check for generators, etc.
return
;
}
if
(
self
::
returnTypeOfFunctionLikeAllowsNull
(
$function
))
{
if
(
$function
->
getUnionType
()->
isEmpty
()
&&
$function
->
hasReturn
())
{
// This has at least one return statement with an expression
if
(!
BlockExitStatusChecker
::
willUnconditionallyThrowOrReturn
(
$stmts_list
))
{
if
(!
$function
->
checkHasSuppressIssueAndIncrementCount
(
'PhanPluginInconsistentReturnFunction'
))
{
self
::
emitIssue
(
$code_base
,
$function
->
getContext
(),
'PhanPluginInconsistentReturnFunction'
,
"Function {FUNCTION} has no return type and will inconsistently return or not return"
,
[(
string
)
$function
->
getFQSEN
()]
);
}
}
}
return
;
}
if
(!
BlockExitStatusChecker
::
willUnconditionallyThrowOrReturn
(
$stmts_list
))
{
if
(!
$function
->
checkHasSuppressIssueAndIncrementCount
(
'PhanPluginAlwaysReturnFunction'
))
{
self
::
emitIssue
(
$code_base
,
$function
->
getContext
(),
'PhanPluginAlwaysReturnFunction'
,
"Function {FUNCTION} has a return type of {TYPE}, but may fail to return a value"
,
[(
string
)
$function
->
getFQSEN
(),
(
string
)
$function
->
getUnionType
()]
);
}
}
}
/**
* @param Func|Method $func
* @return ?Node - returns null if there's no statement list to analyze
*/
private
static
function
getStatementListToAnalyze
(
$func
):
?
Node
{
if
(!
$func
->
hasNode
())
{
return
null
;
}
elseif
(
$func
->
hasYield
())
{
// generators always return Generator.
return
null
;
}
$node
=
$func
->
getNode
();
if
(!
$node
)
{
return
null
;
}
return
$node
->
children
[
'stmts'
];
}
/**
* @param FunctionInterface $func
* @return bool - Is void(absence of a return type) an acceptable return type.
* NOTE: projects can customize this as needed.
*/
private
static
function
returnTypeOfFunctionLikeAllowsNull
(
FunctionInterface
$func
):
bool
{
$real_return_type
=
$func
->
getRealReturnType
();
if
(!
$real_return_type
->
isEmpty
()
&&
!
$real_return_type
->
isType
(
VoidType
::
instance
(
false
)))
{
return
false
;
}
$return_type
=
$func
->
getUnionType
();
return
(
$return_type
->
isEmpty
()
||
$return_type
->
containsNullableLabeled
()
||
$return_type
->
hasType
(
NeverType
::
instance
(
false
))
||
$return_type
->
hasType
(
VoidType
::
instance
(
false
))
||
$return_type
->
hasType
(
NullType
::
instance
(
false
)));
}
}
// Every plugin needs to return an instance of itself at the
// end of the file in which it's defined.
return
new
AlwaysReturnPlugin
();
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Tue, Aug 18, 23:04 (1 d, 8 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
a6/0c/77dd0e33102da757c0fa85159597
Default Alt Text
AlwaysReturnPlugin.php (6 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment