annotate vendor/drupal/coder/coder_sniffer/Drupal/Sniffs/Semantics/FunctionTSniff.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2 /**
Chris@17 3 * \Drupal\Sniffs\Semantics\FunctionTSniff
Chris@0 4 *
Chris@0 5 * @category PHP
Chris@0 6 * @package PHP_CodeSniffer
Chris@0 7 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 8 */
Chris@0 9
Chris@17 10 namespace Drupal\Sniffs\Semantics;
Chris@17 11
Chris@17 12 use PHP_CodeSniffer\Files\File;
Chris@17 13 use PHP_CodeSniffer\Util\Tokens;
Chris@17 14
Chris@0 15 /**
Chris@0 16 * Check the usage of the t() function to not escape translateable strings with back
Chris@0 17 * slashes. Also checks that the first argument does not use string concatenation.
Chris@0 18 *
Chris@0 19 * @category PHP
Chris@0 20 * @package PHP_CodeSniffer
Chris@0 21 * @link http://pear.php.net/package/PHP_CodeSniffer
Chris@0 22 */
Chris@17 23 class FunctionTSniff extends FunctionCall
Chris@0 24 {
Chris@0 25
Chris@0 26 /**
Chris@0 27 * We also want to catch $this->t() calls in Drupal 8.
Chris@0 28 *
Chris@0 29 * @var bool
Chris@0 30 */
Chris@0 31 protected $includeMethodCalls = true;
Chris@0 32
Chris@0 33
Chris@0 34 /**
Chris@0 35 * Returns an array of function names this test wants to listen for.
Chris@0 36 *
Chris@0 37 * @return array
Chris@0 38 */
Chris@0 39 public function registerFunctionNames()
Chris@0 40 {
Chris@0 41 return array(
Chris@0 42 't',
Chris@0 43 'TranslatableMarkup',
Chris@0 44 'TranslationWrapper',
Chris@0 45 );
Chris@0 46
Chris@0 47 }//end registerFunctionNames()
Chris@0 48
Chris@0 49
Chris@0 50 /**
Chris@0 51 * Processes this function call.
Chris@0 52 *
Chris@17 53 * @param \PHP_CodeSniffer\Files\File $phpcsFile The file being scanned.
Chris@17 54 * @param int $stackPtr The position of the function call in
Chris@17 55 * the stack.
Chris@17 56 * @param int $openBracket The position of the opening
Chris@17 57 * parenthesis in the stack.
Chris@17 58 * @param int $closeBracket The position of the closing
Chris@17 59 * parenthesis in the stack.
Chris@0 60 *
Chris@0 61 * @return void
Chris@0 62 */
Chris@0 63 public function processFunctionCall(
Chris@17 64 File $phpcsFile,
Chris@0 65 $stackPtr,
Chris@0 66 $openBracket,
Chris@0 67 $closeBracket
Chris@0 68 ) {
Chris@0 69 $tokens = $phpcsFile->getTokens();
Chris@0 70 $argument = $this->getArgument(1);
Chris@0 71
Chris@0 72 if ($argument === false) {
Chris@0 73 $error = 'Empty calls to t() are not allowed';
Chris@0 74 $phpcsFile->addError($error, $stackPtr, 'EmptyT');
Chris@0 75 return;
Chris@0 76 }
Chris@0 77
Chris@0 78 if ($tokens[$argument['start']]['code'] !== T_CONSTANT_ENCAPSED_STRING) {
Chris@0 79 // Not a translatable string literal.
Chris@0 80 $warning = 'Only string literals should be passed to t() where possible';
Chris@0 81 $phpcsFile->addWarning($warning, $argument['start'], 'NotLiteralString');
Chris@0 82 return;
Chris@0 83 }
Chris@0 84
Chris@0 85 $string = $tokens[$argument['start']]['content'];
Chris@0 86 if ($string === '""' || $string === "''") {
Chris@0 87 $warning = 'Do not pass empty strings to t()';
Chris@0 88 $phpcsFile->addWarning($warning, $argument['start'], 'EmptyString');
Chris@0 89 return;
Chris@0 90 }
Chris@0 91
Chris@17 92 $concatAfter = $phpcsFile->findNext(Tokens::$emptyTokens, ($closeBracket + 1), null, true, null, true);
Chris@0 93 if ($concatAfter !== false && $tokens[$concatAfter]['code'] === T_STRING_CONCAT) {
Chris@17 94 $stringAfter = $phpcsFile->findNext(Tokens::$emptyTokens, ($concatAfter + 1), null, true, null, true);
Chris@0 95 if ($stringAfter !== false
Chris@0 96 && $tokens[$stringAfter]['code'] === T_CONSTANT_ENCAPSED_STRING
Chris@0 97 && $this->checkConcatString($tokens[$stringAfter]['content']) === false
Chris@0 98 ) {
Chris@0 99 $warning = 'Do not concatenate strings to translatable strings, they should be part of the t() argument and you should use placeholders';
Chris@0 100 $phpcsFile->addWarning($warning, $stringAfter, 'ConcatString');
Chris@0 101 }
Chris@0 102 }
Chris@0 103
Chris@0 104 $lastChar = substr($string, -1);
Chris@0 105 if ($lastChar === '"' || $lastChar === "'") {
Chris@0 106 $message = substr($string, 1, -1);
Chris@0 107 if ($message !== trim($message)) {
Chris@0 108 $warning = 'Translatable strings must not begin or end with white spaces, use placeholders with t() for variables';
Chris@0 109 $phpcsFile->addWarning($warning, $argument['start'], 'WhiteSpace');
Chris@0 110 }
Chris@0 111 }
Chris@0 112
Chris@0 113 $concatFound = $phpcsFile->findNext(T_STRING_CONCAT, $argument['start'], $argument['end']);
Chris@0 114 if ($concatFound !== false) {
Chris@0 115 $error = 'Concatenating translatable strings is not allowed, use placeholders instead and only one string literal';
Chris@0 116 $phpcsFile->addError($error, $concatFound, 'Concat');
Chris@0 117 }
Chris@0 118
Chris@0 119 // Check if there is a backslash escaped single quote in the string and
Chris@0 120 // if the string makes use of double quotes.
Chris@0 121 if ($string{0} === "'" && strpos($string, "\'") !== false
Chris@0 122 && strpos($string, '"') === false
Chris@0 123 ) {
Chris@0 124 $warn = 'Avoid backslash escaping in translatable strings when possible, use "" quotes instead';
Chris@0 125 $phpcsFile->addWarning($warn, $argument['start'], 'BackslashSingleQuote');
Chris@0 126 return;
Chris@0 127 }
Chris@0 128
Chris@0 129 if ($string{0} === '"' && strpos($string, '\"') !== false
Chris@0 130 && strpos($string, "'") === false
Chris@0 131 ) {
Chris@0 132 $warn = "Avoid backslash escaping in translatable strings when possible, use '' quotes instead";
Chris@0 133 $phpcsFile->addWarning($warn, $argument['start'], 'BackslashDoubleQuote');
Chris@0 134 }
Chris@0 135
Chris@0 136 }//end processFunctionCall()
Chris@0 137
Chris@0 138
Chris@0 139 /**
Chris@0 140 * Checks if a string can be concatenated with a translatable string.
Chris@0 141 *
Chris@0 142 * @param string $string The string that is concatenated to a t() call.
Chris@0 143 *
Chris@0 144 * @return bool
Chris@0 145 * TRUE if the string is allowed to be concatenated with a translatable
Chris@0 146 * string, FALSE if not.
Chris@0 147 */
Chris@0 148 protected function checkConcatString($string)
Chris@0 149 {
Chris@0 150 // Remove outer quotes, spaces and HTML tags from the original string.
Chris@0 151 $string = trim($string, '"\'');
Chris@0 152 $string = trim(strip_tags($string));
Chris@0 153
Chris@0 154 if ($string === '') {
Chris@0 155 return true;
Chris@0 156 }
Chris@0 157
Chris@17 158 $allowed_items = array(
Chris@17 159 '(',
Chris@17 160 ')',
Chris@17 161 '[',
Chris@17 162 ']',
Chris@17 163 '-',
Chris@17 164 '<',
Chris@17 165 '>',
Chris@17 166 '«',
Chris@17 167 '»',
Chris@17 168 '\n',
Chris@17 169 );
Chris@17 170 foreach ($allowed_items as $item) {
Chris@17 171 if ($item === $string) {
Chris@17 172 return true;
Chris@17 173 }
Chris@0 174 }
Chris@0 175
Chris@0 176 return false;
Chris@0 177
Chris@0 178 }//end checkConcatString()
Chris@0 179
Chris@0 180
Chris@0 181 }//end class