Skip to content

Commit

Permalink
Add phpdoc and phpstan (#94)
Browse files Browse the repository at this point in the history
* Add phpdoc to VariableAnalysisSniff class

* Add phpstan

* Fix phpstan errors

* Add phpstan to CircleCI

* Add phpdoc to Helpers

* Fix phpstan errors for Helpers

* Add phpdoc to ScopeInfo

* Add phpdoc to Constants

* Add phpdoc to VariableInfo

* Add `lint-self` script

* Remove unused variables

* Make lint-self use PWD

* Add lint to circleci
  • Loading branch information
sirbrillig committed Jun 24, 2019
1 parent acfe65c commit 1b1b2b5
Show file tree
Hide file tree
Showing 8 changed files with 533 additions and 96 deletions.
18 changes: 17 additions & 1 deletion .circleci/config.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,25 @@
version: 2
jobs:
build:
build_php7:
docker:
- image: circleci/php:7.3.1
steps:
- checkout
- run: COMPOSER=composer.json composer install
- run: COMPOSER=composer.json composer test
- run: COMPOSER=composer.json composer phpstan
- run: COMPOSER=composer.json composer lint
- run: COMPOSER=composer.json composer lint-self
build_php5:
docker:
- image: circleci/php:5.6.40-zts-stretch-node-browsers-legacy
steps:
- checkout
- run: COMPOSER=composer.circleci.json composer install
- run: COMPOSER=composer.circleci.json composer test
workflows:
version: 2
build_php_versions:
jobs:
- build_php5
- build_php7
9 changes: 7 additions & 2 deletions VariableAnalysis/Lib/Constants.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ class Constants {
* Array of known pass-by-reference functions and the argument(s) which are passed
* by reference, the arguments are numbered starting from 1 and an elipsis '...'
* means all argument numbers after the previous should be considered pass-by-reference.
*
* @return array[]
*/
public static function getPassByReferenceFunctions() {
return [
Expand Down Expand Up @@ -35,7 +37,6 @@ public static function getPassByReferenceFunctions() {
'array_walk_recursive' => [1],
'arsort' => [1],
'asort' => [1],
'asort' => [1],
'bindColumn' => [2],
'bindParam' => [2],
'bind_param' => [2, 3, '...'],
Expand Down Expand Up @@ -202,7 +203,6 @@ public static function getPassByReferenceFunctions() {
'sqlite_open' => [3],
'sqlite_popen' => [3],
'sqlite_query' => [4],
'sqlite_query' => [4],
'sqlite_unbuffered_query' => [4],
'sscanf' => [3, '...'],
'str_ireplace' => [4],
Expand Down Expand Up @@ -238,6 +238,9 @@ public static function getPassByReferenceFunctions() {
];
}

/**
* @return array[]
*/
public static function getWordPressPassByReferenceFunctions() {
return [
'wp_parse_str' => [2],
Expand All @@ -247,6 +250,8 @@ public static function getWordPressPassByReferenceFunctions() {

/**
* A regexp for matching variable names in double-quoted strings.
*
* @return string
*/
public static function getDoubleQuotedVarRegexp() {
return '|(?<!\\\\)(?:\\\\{2})*\${?([a-zA-Z0-9_]+)}?|';
Expand Down
124 changes: 111 additions & 13 deletions VariableAnalysis/Lib/Helpers.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,39 +5,73 @@
use PHP_CodeSniffer\Files\File;

class Helpers {
/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int|bool
*/
public static function findContainingOpeningSquareBracket(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();
$previousStatementPtr = self::getPreviousStatementPtr($phpcsFile, $stackPtr);
return $phpcsFile->findPrevious(T_OPEN_SHORT_ARRAY, $stackPtr - 1, $previousStatementPtr);
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int|bool
*/
public static function findContainingClosingSquareBracket(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();
$endOfStatementPtr = $phpcsFile->findNext([T_SEMICOLON], $stackPtr + 1);
if (! $endOfStatementPtr) {
if (is_bool($endOfStatementPtr)) {
return false;
}
return $phpcsFile->findNext(T_CLOSE_SHORT_ARRAY, $stackPtr + 1, $endOfStatementPtr);
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int
*/
public static function getPreviousStatementPtr(File $phpcsFile, $stackPtr) {
return $phpcsFile->findPrevious([T_SEMICOLON, T_CLOSE_CURLY_BRACKET], $stackPtr - 1) ?: 1;
$result = $phpcsFile->findPrevious([T_SEMICOLON, T_CLOSE_CURLY_BRACKET], $stackPtr - 1);
return is_bool($result) ? 1 : $result;
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int|bool
*/
public static function findContainingOpeningBracket(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();
if (isset($tokens[$stackPtr]['nested_parenthesis'])) {
$openPtrs = array_keys($tokens[$stackPtr]['nested_parenthesis']);
return end($openPtrs);
return (int)end($openPtrs);
}
return false;
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int|bool
*/
public static function findParenthesisOwner(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();
return $phpcsFile->findPrevious(T_WHITESPACE, $stackPtr - 1, null, true);
}

/**
* @param File $phpcsFile
* @param int[] $conditions
*
* @return bool
*/
public static function areAnyConditionsAClosure(File $phpcsFile, array $conditions) {
// self within a closure is invalid
$tokens = $phpcsFile->getTokens();
Expand All @@ -50,6 +84,12 @@ public static function areAnyConditionsAClosure(File $phpcsFile, array $conditio
return false;
}


/**
* @param int[] $conditions
*
* @return bool
*/
public static function areAnyConditionsAClass(array $conditions) {
foreach (array_reverse($conditions, true) as $scopePtr => $scopeCode) {
if ($scopeCode === T_CLASS || $scopeCode === T_TRAIT) {
Expand All @@ -59,6 +99,11 @@ public static function areAnyConditionsAClass(array $conditions) {
return false;
}

/**
* @param int[] $conditions
*
* @return bool
*/
public static function areConditionsWithinFunctionBeforeClass(array $conditions) {
// Return true if the token conditions are within a function before
// they are within a class.
Expand All @@ -74,6 +119,12 @@ public static function areConditionsWithinFunctionBeforeClass(array $conditions)
return false;
}

/**
* @param File $phpcsFile
* @param int $openPtr
*
* @return int|bool
*/
public static function findPreviousFunctionPtr(File $phpcsFile, $openPtr) {
// Function names are T_STRING, and return-by-reference is T_BITWISE_AND,
// so we look backwards from the opening bracket for the first thing that
Expand All @@ -87,13 +138,13 @@ public static function findPreviousFunctionPtr(File $phpcsFile, $openPtr) {
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int|false
* @return int|bool
*/
public static function findFunctionCall(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();

$openPtr = Helpers::findContainingOpeningBracket($phpcsFile, $stackPtr);
if ($openPtr) {
if (is_int($openPtr)) {
// First non-whitespace thing and see if it's a T_STRING function name
$functionPtr = $phpcsFile->findPrevious(T_WHITESPACE, $openPtr - 1, null, true, null, true);
if ($tokens[$functionPtr]['code'] === T_STRING) {
Expand All @@ -103,6 +154,12 @@ public static function findFunctionCall(File $phpcsFile, $stackPtr) {
return false;
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return array[]|false
*/
public static function findFunctionCallArguments(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();

Expand All @@ -129,19 +186,27 @@ public static function findFunctionCallArguments(File $phpcsFile, $stackPtr) {
$argPtrs = [];
$lastPtr = $openPtr;
$lastArgComma = $openPtr;
while (($nextPtr = $phpcsFile->findNext(T_COMMA, $lastPtr + 1, $closePtr)) !== false) {
$nextPtr = $phpcsFile->findNext(T_COMMA, $lastPtr + 1, $closePtr);
while (is_int($nextPtr)) {
if (Helpers::findContainingOpeningBracket($phpcsFile, $nextPtr) == $openPtr) {
// Comma is at our level of brackets, it's an argument delimiter.
array_push($argPtrs, range($lastArgComma + 1, $nextPtr - 1));
$lastArgComma = $nextPtr;
}
$lastPtr = $nextPtr;
$nextPtr = $phpcsFile->findNext(T_COMMA, $lastPtr + 1, $closePtr);
}
array_push($argPtrs, range($lastArgComma + 1, $closePtr - 1));

return $argPtrs;
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int
*/
public static function findWhereAssignExecuted(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();

Expand Down Expand Up @@ -171,6 +236,12 @@ public static function findWhereAssignExecuted(File $phpcsFile, $stackPtr) {
return $assignEndTokens[0];
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int|bool
*/
public static function isNextThingAnAssign(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();

Expand All @@ -184,16 +255,27 @@ public static function isNextThingAnAssign(File $phpcsFile, $stackPtr) {
return false;
}

/**
* @param string $varName
*
* @return string
*/
public static function normalizeVarName($varName) {
return preg_replace('/[{}$]/', '', $varName);
$result = preg_replace('/[{}$]/', '', $varName);
return $result ? $result : $varName;
}

/**
* @param File $phpcsFile
* @param int $stackPtr
*
* @return int|bool
*/
public static function findFunctionPrototype(File $phpcsFile, $stackPtr) {
$tokens = $phpcsFile->getTokens();
$token = $tokens[$stackPtr];

$openPtr = Helpers::findContainingOpeningBracket($phpcsFile, $stackPtr);
if ($openPtr === false) {
if (! is_int($openPtr)) {
return false;
}
$functionPtr = Helpers::findPreviousFunctionPtr($phpcsFile, $openPtr);
Expand Down Expand Up @@ -226,7 +308,7 @@ public static function findVariableScope(File $phpcsFile, $stackPtr) {
}

$scopePtr = Helpers::findFunctionPrototype($phpcsFile, $stackPtr);
if ($scopePtr !== false) {
if (is_int($scopePtr)) {
return $scopePtr;
}

Expand All @@ -239,6 +321,11 @@ public static function findVariableScope(File $phpcsFile, $stackPtr) {
return 0;
}

/**
* @param string $message
*
* @return void
*/
public static function debug($message) {
if (! defined('PHP_CODESNIFFER_VERBOSITY')) {
return;
Expand All @@ -247,4 +334,15 @@ public static function debug($message) {
echo PHP_EOL . "VariableAnalysisSniff: DEBUG: $message" . PHP_EOL;
}
}

/**
* @param string $pattern
* @param string $value
*
* @return string[]
*/
public static function splitStringToArray($pattern, $value) {
$result = preg_split($pattern, $value);
return is_array($result) ? $result : [];
}
}
9 changes: 7 additions & 2 deletions VariableAnalysis/Lib/ScopeInfo.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,14 @@
* Holds details of a scope.
*/
class ScopeInfo {
/**
* @var int
*/
public $owner;
public $opener;
public $closer;

/**
* @var VariableInfo[]
*/
public $variables = [];

public function __construct($currScope) {
Expand Down
Loading

0 comments on commit 1b1b2b5

Please sign in to comment.