public function process(XHPASTNode $root)
 {
     $logical_ands = $root->selectTokensOfType('T_LOGICAL_AND');
     $logical_ors = $root->selectTokensOfType('T_LOGICAL_OR');
     foreach ($logical_ands as $logical_and) {
         $this->raiseLintAtToken($logical_and, pht('Use `%s` instead of `%s`.', '&&', 'and'), '&&');
     }
     foreach ($logical_ors as $logical_or) {
         $this->raiseLintAtToken($logical_or, pht('Use `%s` instead of `%s`.', '||', 'or'), '||');
     }
 }
 public function process(XHPASTNode $root)
 {
     $tokens = $root->selectTokensOfType('T_ELSEIF');
     foreach ($tokens as $token) {
         $this->raiseLintAtToken($token, pht('Usage of `%s` is preferred over `%s`.', 'else if', 'elseif'), 'else if');
     }
 }
 public function process(XHPASTNode $root)
 {
     $inline_html = $root->selectDescendantsOfType('n_INLINE_HTML');
     if ($inline_html) {
         return;
     }
     foreach ($root->selectTokensOfType('T_CLOSE_TAG') as $token) {
         $this->raiseLintAtToken($token, pht('Do not use the PHP closing tag, "%s".', '?>'));
     }
 }
 public function process(XHPASTNode $root)
 {
     foreach ($root->selectTokensOfType('T_COMMENT') as $comment) {
         $value = $comment->getValue();
         if ($value[0] !== '#') {
             continue;
         }
         $this->raiseLintAtOffset($comment->getOffset(), pht('Use `%s` single-line comments, not `%s`.', '//', '#'), '#', preg_match('/^#\\S/', $value) ? '// ' : '//');
     }
 }
 public function process(XHPASTNode $root)
 {
     $tokens = $root->selectTokensOfType(';');
     foreach ($tokens as $token) {
         $prev = $token->getPrevToken();
         if ($prev->isAnyWhitespace()) {
             $this->raiseLintAtToken($prev, pht('Space found before semicolon.'), '');
         }
     }
 }
 public function process(XHPASTNode $root)
 {
     foreach ($root->selectTokensOfType('T_COMMENT') as $comment) {
         $value = $comment->getValue();
         if ($value[0] !== '#') {
             $match = null;
             if (preg_match('@^(/[/*]+)[^/*\\s]@', $value, $match)) {
                 $this->raiseLintAtOffset($comment->getOffset(), pht('Put space after comment start.'), $match[1], $match[1] . ' ');
             }
         }
     }
 }
 public function process(XHPASTNode $root)
 {
     $inline_html = $root->selectTokensOfType('T_INLINE_HTML');
     foreach ($inline_html as $html) {
         if (substr($html->getValue(), 0, 2) == '#!') {
             // Ignore shebang lines.
             continue;
         }
         if (preg_match('/^\\s*$/', $html->getValue())) {
             continue;
         }
         $this->raiseLintAtToken($html, pht('PHP files must only contain PHP code.'));
         break;
     }
 }
 public function process(XHPASTNode $root)
 {
     $double_colons = $root->selectTokensOfType('T_PAAMAYIM_NEKUDOTAYIM');
     foreach ($double_colons as $double_colon) {
         $tokens = $double_colon->getNonsemanticTokensBefore() + $double_colon->getNonsemanticTokensAfter();
         foreach ($tokens as $token) {
             if ($token->isAnyWhitespace()) {
                 if (strpos($token->getValue(), "\n") !== false) {
                     continue;
                 }
                 $this->raiseLintAtToken($token, pht('Unnecessary whitespace around paamayim nekudotayim ' . '(double colon) operator.'), '');
             }
         }
     }
 }
 public function process(XHPASTNode $root)
 {
     $class_declarations = $root->selectDescendantsOfType('n_CLASS_DECLARATION');
     foreach ($class_declarations as $class_declaration) {
         $class_name = $class_declaration->getChildOfType(1, 'n_CLASS_NAME')->getConcreteString();
         $class_static_accesses = $class_declaration->selectDescendantsOfType('n_CLASS_STATIC_ACCESS');
         $closures = $this->getAnonymousClosures($class_declaration);
         foreach ($class_static_accesses as $class_static_access) {
             $double_colons = $class_static_access->selectTokensOfType('T_PAAMAYIM_NEKUDOTAYIM');
             $class_ref = $class_static_access->getChildByIndex(0);
             if ($class_ref->getTypeName() != 'n_CLASS_NAME') {
                 continue;
             }
             $class_ref_name = $class_ref->getConcreteString();
             if (strtolower($class_name) == strtolower($class_ref_name)) {
                 $in_closure = false;
                 foreach ($closures as $closure) {
                     if ($class_ref->isDescendantOf($closure)) {
                         $in_closure = true;
                         break;
                     }
                 }
                 if (version_compare($this->version, '5.4.0', '>=') || !$in_closure) {
                     $this->raiseLintAtNode($class_ref, pht('Use `%s` for local static member references.', 'self::'), 'self');
                 }
             }
             static $self_refs = array('parent', 'self', 'static');
             if (!in_array(strtolower($class_ref_name), $self_refs)) {
                 continue;
             }
             if ($class_ref_name != strtolower($class_ref_name)) {
                 $this->raiseLintAtNode($class_ref, pht('PHP keywords should be lowercase.'), strtolower($class_ref_name));
             }
         }
     }
     $double_colons = $root->selectTokensOfType('T_PAAMAYIM_NEKUDOTAYIM');
     foreach ($double_colons as $double_colon) {
         $tokens = $double_colon->getNonsemanticTokensBefore() + $double_colon->getNonsemanticTokensAfter();
         foreach ($tokens as $token) {
             if ($token->isAnyWhitespace()) {
                 if (strpos($token->getValue(), "\n") !== false) {
                     continue;
                 }
                 $this->raiseLintAtToken($token, pht('Unnecessary whitespace around double colon operator.'), '');
             }
         }
     }
 }
 public function process(XHPASTNode $root)
 {
     $operators = $root->selectTokensOfType('T_OBJECT_OPERATOR');
     foreach ($operators as $operator) {
         $before = $operator->getNonsemanticTokensBefore();
         $after = $operator->getNonsemanticTokensAfter();
         if ($before) {
             $value = implode('', mpull($before, 'getValue'));
             if (strpos($value, "\n") !== false) {
                 continue;
             }
             $this->raiseLintAtOffset(head($before)->getOffset(), pht('There should be no whitespace before the object operator.'), $value, '');
         }
         if ($after) {
             $this->raiseLintAtOffset(head($after)->getOffset(), pht('There should be no whitespace after the object operator.'), implode('', mpull($before, 'getValue')), '');
         }
     }
 }
 public function process(XHPASTNode $root)
 {
     $tokens = $root->selectTokensOfType('T_OPEN_TAG');
     foreach ($tokens as $token) {
         for ($next = $token->getNextToken(); $next; $next = $next->getNextToken()) {
             if ($next->getTypeName() == 'T_WHITESPACE' && preg_match('/\\n\\s*\\n/', $next->getValue())) {
                 continue 2;
             }
             if ($token->getLineNumber() != $next->getLineNumber()) {
                 break;
             }
             if ($next->getTypeName() == 'T_CLOSE_TAG') {
                 continue 2;
             }
         }
         $next = $token->getNextToken();
         $this->raiseLintAtToken($next, pht('`%s` should be separated from code by an empty line.', '<?php'), "\n" . $next->getValue());
     }
 }
 public function process(XHPASTNode $root)
 {
     $tokens = $root->selectTokensOfType('.');
     foreach ($tokens as $token) {
         $prev = $token->getPrevToken();
         $next = $token->getNextToken();
         foreach (array('prev' => $prev, 'next' => $next) as $wtoken) {
             if ($wtoken->getTypeName() !== 'T_WHITESPACE') {
                 continue;
             }
             $value = $wtoken->getValue();
             if (strpos($value, "\n") !== false) {
                 // If the whitespace has a newline, it's conventional.
                 continue;
             }
             $next = $wtoken->getNextToken();
             if ($next && $next->getTypeName() === 'T_COMMENT') {
                 continue;
             }
             $this->raiseLintAtToken($wtoken, pht('Convention: no spaces around string concatenation operator.'), '');
         }
     }
 }
 private function lintPHP53Features(XHPASTNode $root)
 {
     $functions = $root->selectTokensOfType('T_FUNCTION');
     foreach ($functions as $function) {
         $next = $function->getNextToken();
         while ($next) {
             if ($next->isSemantic()) {
                 break;
             }
             $next = $next->getNextToken();
         }
         if ($next) {
             if ($next->getTypeName() === '(') {
                 $this->raiseLintAtToken($function, pht('This codebase targets PHP %s, but anonymous ' . 'functions were not introduced until PHP 5.3.', $this->version));
             }
         }
     }
     $namespaces = $root->selectTokensOfType('T_NAMESPACE');
     foreach ($namespaces as $namespace) {
         $this->raiseLintAtToken($namespace, pht('This codebase targets PHP %s, but namespaces were not ' . 'introduced until PHP 5.3.', $this->version));
     }
     // NOTE: This is only "use x;", in anonymous functions the node type is
     // n_LEXICAL_VARIABLE_LIST even though both tokens are T_USE.
     $uses = $root->selectDescendantsOfType('n_USE_LIST');
     foreach ($uses as $use) {
         $this->raiseLintAtNode($use, pht('This codebase targets PHP %s, but namespaces were not ' . 'introduced until PHP 5.3.', $this->version));
     }
     $statics = $root->selectDescendantsOfType('n_CLASS_STATIC_ACCESS');
     foreach ($statics as $static) {
         $name = $static->getChildByIndex(0);
         if ($name->getTypeName() != 'n_CLASS_NAME') {
             continue;
         }
         if ($name->getConcreteString() === 'static') {
             $this->raiseLintAtNode($name, pht('This codebase targets PHP %s, but `%s` was not ' . 'introduced until PHP 5.3.', $this->version, 'static::'));
         }
     }
     $ternaries = $root->selectDescendantsOfType('n_TERNARY_EXPRESSION');
     foreach ($ternaries as $ternary) {
         $yes = $ternary->getChildByIndex(2);
         if ($yes->getTypeName() === 'n_EMPTY') {
             $this->raiseLintAtNode($ternary, pht('This codebase targets PHP %s, but short ternary was ' . 'not introduced until PHP 5.3.', $this->version));
         }
     }
     $heredocs = $root->selectDescendantsOfType('n_HEREDOC');
     foreach ($heredocs as $heredoc) {
         if (preg_match('/^<<<[\'"]/', $heredoc->getConcreteString())) {
             $this->raiseLintAtNode($heredoc, pht('This codebase targets PHP %s, but nowdoc was not ' . 'introduced until PHP 5.3.', $this->version));
         }
     }
 }
 public function process(XHPASTNode $root)
 {
     foreach ($root->selectTokensOfType('T_CLOSE_TAG') as $token) {
         $this->raiseLintAtToken($token, pht('Do not use the PHP closing tag, "%s".', '?>'));
     }
 }
 public function process(XHPASTNode $root)
 {
     $expressions = $root->selectDescendantsOfType('n_BINARY_EXPRESSION');
     foreach ($expressions as $expression) {
         $operator = $expression->getChildByIndex(1);
         $operator_value = $operator->getConcreteString();
         list($before, $after) = $operator->getSurroundingNonsemanticTokens();
         $replace = null;
         if (empty($before) && empty($after)) {
             $replace = " {$operator_value} ";
         } else {
             if (empty($before)) {
                 $replace = " {$operator_value}";
             } else {
                 if (empty($after)) {
                     $replace = "{$operator_value} ";
                 }
             }
         }
         if ($replace !== null) {
             $this->raiseLintAtNode($operator, pht('Convention: logical and arithmetic operators should be ' . 'surrounded by whitespace.'), $replace);
         }
     }
     $tokens = $root->selectTokensOfType(',');
     foreach ($tokens as $token) {
         $next = $token->getNextToken();
         switch ($next->getTypeName()) {
             case ')':
             case 'T_WHITESPACE':
                 break;
             default:
                 $this->raiseLintAtToken($token, pht('Convention: comma should be followed by space.'), ', ');
                 break;
         }
     }
     $tokens = $root->selectTokensOfType('T_DOUBLE_ARROW');
     foreach ($tokens as $token) {
         $prev = $token->getPrevToken();
         $next = $token->getNextToken();
         $prev_type = $prev->getTypeName();
         $next_type = $next->getTypeName();
         $prev_space = $prev_type === 'T_WHITESPACE';
         $next_space = $next_type === 'T_WHITESPACE';
         $replace = null;
         if (!$prev_space && !$next_space) {
             $replace = ' => ';
         } else {
             if ($prev_space && !$next_space) {
                 $replace = '=> ';
             } else {
                 if (!$prev_space && $next_space) {
                     $replace = ' =>';
                 }
             }
         }
         if ($replace !== null) {
             $this->raiseLintAtToken($token, pht('Convention: double arrow should be surrounded by whitespace.'), $replace);
         }
     }
     $parameters = $root->selectDescendantsOfType('n_DECLARATION_PARAMETER');
     foreach ($parameters as $parameter) {
         if ($parameter->getChildByIndex(2)->getTypeName() == 'n_EMPTY') {
             continue;
         }
         $operator = head($parameter->selectTokensOfType('='));
         $before = $operator->getNonsemanticTokensBefore();
         $after = $operator->getNonsemanticTokensAfter();
         $replace = null;
         if (empty($before) && empty($after)) {
             $replace = ' = ';
         } else {
             if (empty($before)) {
                 $replace = ' =';
             } else {
                 if (empty($after)) {
                     $replace = '= ';
                 }
             }
         }
         if ($replace !== null) {
             $this->raiseLintAtToken($operator, pht('Convention: logical and arithmetic operators should be ' . 'surrounded by whitespace.'), $replace);
         }
     }
 }
예제 #16
0
 protected function lintSemicolons(XHPASTNode $root)
 {
     $tokens = $root->selectTokensOfType(';');
     foreach ($tokens as $token) {
         $prev = $token->getPrevToken();
         if ($prev->isAnyWhitespace()) {
             $this->raiseLintAtToken($prev, self::LINT_SEMICOLON_SPACING, pht('Space found before semicolon.'), '');
         }
     }
 }