Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F1431721
Fixers.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
Fixers.php
View Options
<?php
declare
(
strict_types
=
1
);
namespace
PHPDocRedundantPlugin
;
use
Microsoft\PhpParser
;
use
Microsoft\PhpParser\FunctionLike
;
use
Microsoft\PhpParser\Node\Expression\AnonymousFunctionCreationExpression
;
use
Microsoft\PhpParser\Node\MethodDeclaration
;
use
Microsoft\PhpParser\Node\Statement\FunctionDeclaration
;
use
Microsoft\PhpParser\ParseContext
;
use
Microsoft\PhpParser\PhpTokenizer
;
use
Microsoft\PhpParser\Token
;
use
Microsoft\PhpParser\TokenKind
;
use
Phan\AST\TolerantASTConverter\NodeUtils
;
use
Phan\CodeBase
;
use
Phan\IssueInstance
;
use
Phan\Language\Element\Comment\Builder
;
use
Phan\Library\FileCacheEntry
;
use
Phan\Library\StringUtil
;
use
Phan\Plugin\Internal\IssueFixingPlugin\FileEdit
;
use
Phan\Plugin\Internal\IssueFixingPlugin\FileEditSet
;
/**
* This plugin implements --automatic-fix for PHPDocRedundantPlugin
*/
class
Fixers
{
/**
* Remove a redundant phpdoc return type from the real signature
* @param CodeBase $code_base @unused-param
*/
public
static
function
fixRedundantFunctionLikeComment
(
CodeBase
$code_base
,
FileCacheEntry
$contents
,
IssueInstance
$instance
):
?
FileEditSet
{
$params
=
$instance
->
getTemplateParameters
();
$name
=
$params
[
0
];
$encoded_comment
=
$params
[
1
];
// @phan-suppress-next-line PhanPartialTypeMismatchArgument
$declaration
=
self
::
findFunctionLikeDeclaration
(
$contents
,
$instance
->
getLine
(),
$name
);
if
(!
$declaration
)
{
return
null
;
}
return
self
::
computeEditsToRemoveFunctionLikeComment
(
$contents
,
$declaration
,
(
string
)
$encoded_comment
);
}
private
static
function
computeEditsToRemoveFunctionLikeComment
(
FileCacheEntry
$contents
,
FunctionLike
$declaration
,
string
$encoded_comment
):
?
FileEditSet
{
if
(!
$declaration
instanceof
PhpParser\Node
)
{
// impossible
return
null
;
}
$comment_token
=
self
::
getDocCommentToken
(
$declaration
);
if
(!
$comment_token
)
{
return
null
;
}
$file_contents
=
$contents
->
getContents
();
$comment
=
$comment_token
->
getText
(
$file_contents
);
$actual_encoded_comment
=
StringUtil
::
encodeValue
(
$comment
);
if
(
$actual_encoded_comment
!==
$encoded_comment
)
{
return
null
;
}
return
self
::
computeEditSetToDeleteComment
(
$file_contents
,
$comment_token
);
}
private
static
function
computeEditSetToDeleteComment
(
string
$file_contents
,
Token
$comment_token
):
FileEditSet
{
// get the byte where the `)` of the argument list ends
$last_byte_index
=
$comment_token
->
getEndPosition
();
$first_byte_index
=
$comment_token
->
start
;
// Skip leading whitespace and the previous newline, if those were found
for
(;
$first_byte_index
>
0
;
$first_byte_index
--)
{
$prev_byte
=
$file_contents
[
$first_byte_index
-
1
];
switch
(
$prev_byte
)
{
case
" "
:
case
"
\t
"
:
// keep skipping previous bytes of whitespace
break
;
case
"
\n
"
:
$first_byte_index
--;
if
(
$first_byte_index
>
0
&&
$file_contents
[
$first_byte_index
-
1
]
===
"
\r
"
)
{
$first_byte_index
--;
}
break
2
;
case
"
\r
"
:
$first_byte_index
--;
break
2
;
default
:
// This is not whitespace, so stop.
break
2
;
}
}
$file_edit
=
new
FileEdit
(
$first_byte_index
,
$last_byte_index
,
''
);
return
new
FileEditSet
([
$file_edit
]);
}
/**
* Add a missing return type to the real signature
* @param CodeBase $code_base @unused-param
*/
public
static
function
fixRedundantReturnComment
(
CodeBase
$code_base
,
FileCacheEntry
$contents
,
IssueInstance
$instance
):
?
FileEditSet
{
$lineno
=
$instance
->
getLine
();
$file_lines
=
$contents
->
getLines
();
$line
=
\trim
(
$file_lines
[
$lineno
]);
// @phan-suppress-next-line PhanAccessClassConstantInternal
if
(!
\preg_match
(
Builder
::
RETURN_COMMENT_REGEX
,
$line
))
{
return
null
;
}
$first_deleted_line
=
$lineno
;
$last_deleted_line
=
$lineno
;
$is_blank_comment_line
=
static
function
(
int
$i
)
use
(
$file_lines
):
bool
{
return
\trim
(
$file_lines
[
$i
]
??
''
)
===
'*'
;
};
while
(
$is_blank_comment_line
(
$first_deleted_line
-
1
))
{
$first_deleted_line
--;
}
while
(
$is_blank_comment_line
(
$last_deleted_line
+
1
))
{
$last_deleted_line
++;
}
$start_offset
=
$contents
->
getLineOffset
(
$first_deleted_line
);
$end_offset
=
$contents
->
getLineOffset
(
$last_deleted_line
+
1
);
if
(!
$start_offset
||
!
$end_offset
)
{
return
null
;
}
// Return an edit to delete the `(at)return RedundantType` and the surrounding blank comment lines
return
new
FileEditSet
([
new
FileEdit
(
$start_offset
,
$end_offset
,
''
)]);
}
/**
* @suppress PhanThrowTypeAbsentForCall
* @suppress PhanUndeclaredClassMethod
* @suppress UnusedSuppression false positive for PhpTokenizer with polyfill due to https://github.com/Microsoft/tolerant-php-parser/issues/292
*/
private
static
function
getDocCommentToken
(
PhpParser\Node
$node
):
?
Token
{
$leadingTriviaText
=
$node
->
getLeadingCommentAndWhitespaceText
();
$leadingTriviaTokens
=
PhpTokenizer
::
getTokensArrayFromContent
(
$leadingTriviaText
,
ParseContext
::
SourceElements
,
$node
->
getFullStartPosition
(),
false
);
for
(
$i
=
\count
(
$leadingTriviaTokens
)
-
1
;
$i
>=
0
;
$i
--)
{
$token
=
$leadingTriviaTokens
[
$i
];
if
(
$token
->
kind
===
TokenKind
::
DocCommentToken
)
{
return
$token
;
}
}
return
null
;
}
private
static
function
findFunctionLikeDeclaration
(
FileCacheEntry
$contents
,
int
$line
,
string
$name
):
?
FunctionLike
{
$candidates
=
[];
foreach
(
$contents
->
getNodesAtLine
(
$line
)
as
$node
)
{
if
(
$node
instanceof
FunctionDeclaration
||
$node
instanceof
MethodDeclaration
)
{
$name_node
=
$node
->
name
;
if
(!
$name_node
)
{
continue
;
}
$declaration_name
=
(
new
NodeUtils
(
$contents
->
getContents
()))->
tokenToString
(
$name_node
);
if
(
$declaration_name
===
$name
)
{
$candidates
[]
=
$node
;
}
}
elseif
(
$node
instanceof
AnonymousFunctionCreationExpression
)
{
if
(
\preg_match
(
'/^Closure
\(
/'
,
$name
))
{
$candidates
[]
=
$node
;
}
}
}
if
(
\count
(
$candidates
)
===
1
)
{
return
$candidates
[
0
];
}
return
null
;
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Sat, May 16, 21:00 (1 d, 14 h)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
f7/23/b54e6aa4eddeaba4beee5f865809
Default Alt Text
Fixers.php (6 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment