* @copyright 2020 Squiz Pty Ltd (ABN 77 084 670 600)
* @license https://github.com/PHPCSStandards/PHP_CodeSniffer/blob/master/licence.txt BSD Licence
*/
namespace PHP_CodeSniffer\Tests\Core\Tokenizers\PHP;
use PHP_CodeSniffer\Tests\Core\Tokenizers\AbstractTokenizerTestCase;
use PHP_CodeSniffer\Util\Tokens;
final class ContextSensitiveKeywordsTest extends AbstractTokenizerTestCase
{
/**
* Test that context sensitive keyword is tokenized as string when it should be string.
*
* @param string $testMarker The comment which prefaces the target token in the test file.
*
* @dataProvider dataStrings
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
*
* @return void
*/
public function testStrings($testMarker)
{
$tokens = $this->phpcsFile->getTokens();
$target = $this->getTargetToken($testMarker, (Tokens::$contextSensitiveKeywords + [T_STRING]));
$tokenArray = $tokens[$target];
$this->assertSame(T_STRING, $tokenArray['code'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (code)');
$this->assertSame('T_STRING', $tokenArray['type'], 'Token tokenized as '.$tokenArray['type'].', not T_STRING (type)');
}//end testStrings()
/**
* Data provider.
*
* @see testStrings()
*
* @return array>
*/
public static function dataStrings()
{
return [
'constant declaration: abstract' => ['/* testAbstract */'],
'constant declaration: array' => ['/* testArray */'],
'constant declaration: as' => ['/* testAs */'],
'constant declaration: break' => ['/* testBreak */'],
'constant declaration: callable' => ['/* testCallable */'],
'constant declaration: case' => ['/* testCase */'],
'constant declaration: catch' => ['/* testCatch */'],
'constant declaration: class' => ['/* testClass */'],
'constant declaration: clone' => ['/* testClone */'],
'constant declaration: const' => ['/* testConst */'],
'constant declaration: continue' => ['/* testContinue */'],
'constant declaration: declare' => ['/* testDeclare */'],
'constant declaration: default' => ['/* testDefault */'],
'constant declaration: do' => ['/* testDo */'],
'constant declaration: echo' => ['/* testEcho */'],
'constant declaration: else' => ['/* testElse */'],
'constant declaration: elseif' => ['/* testElseIf */'],
'constant declaration: empty' => ['/* testEmpty */'],
'constant declaration: enddeclare' => ['/* testEndDeclare */'],
'constant declaration: endfor' => ['/* testEndFor */'],
'constant declaration: endforeach' => ['/* testEndForeach */'],
'constant declaration: endif' => ['/* testEndIf */'],
'constant declaration: endswitch' => ['/* testEndSwitch */'],
'constant declaration: endwhile' => ['/* testEndWhile */'],
'constant declaration: enum' => ['/* testEnum */'],
'constant declaration: eval' => ['/* testEval */'],
'constant declaration: exit' => ['/* testExit */'],
'constant declaration: extends' => ['/* testExtends */'],
'constant declaration: final' => ['/* testFinal */'],
'constant declaration: finally' => ['/* testFinally */'],
'constant declaration: fn' => ['/* testFn */'],
'constant declaration: for' => ['/* testFor */'],
'constant declaration: foreach' => ['/* testForeach */'],
'constant declaration: function' => ['/* testFunction */'],
'constant declaration: global' => ['/* testGlobal */'],
'constant declaration: goto' => ['/* testGoto */'],
'constant declaration: if' => ['/* testIf */'],
'constant declaration: implements' => ['/* testImplements */'],
'constant declaration: include' => ['/* testInclude */'],
'constant declaration: include_once' => ['/* testIncludeOnce */'],
'constant declaration: instanceof' => ['/* testInstanceOf */'],
'constant declaration: insteadof' => ['/* testInsteadOf */'],
'constant declaration: interface' => ['/* testInterface */'],
'constant declaration: isset' => ['/* testIsset */'],
'constant declaration: list' => ['/* testList */'],
'constant declaration: match' => ['/* testMatch */'],
'constant declaration: namespace' => ['/* testNamespace */'],
'constant declaration: new' => ['/* testNew */'],
'constant declaration: print' => ['/* testPrint */'],
'constant declaration: private' => ['/* testPrivate */'],
'constant declaration: protected' => ['/* testProtected */'],
'constant declaration: public' => ['/* testPublic */'],
'constant declaration: readonly' => ['/* testReadonly */'],
'constant declaration: require' => ['/* testRequire */'],
'constant declaration: require_once' => ['/* testRequireOnce */'],
'constant declaration: return' => ['/* testReturn */'],
'constant declaration: static' => ['/* testStatic */'],
'constant declaration: switch' => ['/* testSwitch */'],
'constant declaration: throws' => ['/* testThrows */'],
'constant declaration: trait' => ['/* testTrait */'],
'constant declaration: try' => ['/* testTry */'],
'constant declaration: unset' => ['/* testUnset */'],
'constant declaration: use' => ['/* testUse */'],
'constant declaration: var' => ['/* testVar */'],
'constant declaration: while' => ['/* testWhile */'],
'constant declaration: yield' => ['/* testYield */'],
'constant declaration: yield_from' => ['/* testYieldFrom */'],
'constant declaration: and' => ['/* testAnd */'],
'constant declaration: or' => ['/* testOr */'],
'constant declaration: xor' => ['/* testXor */'],
'constant declaration: array in type' => ['/* testArrayIsTstringInConstType */'],
'constant declaration: array, name after type' => ['/* testArrayNameForTypedConstant */'],
'constant declaration: static, name after type' => ['/* testStaticIsNameForTypedConstant */'],
'constant declaration: private, name after type' => ['/* testPrivateNameForUnionTypedConstant */'],
'constant declaration: final, name after type' => ['/* testFinalNameForIntersectionTypedConstant */'],
'namespace declaration: class' => ['/* testKeywordAfterNamespaceShouldBeString */'],
'namespace declaration (partial): my' => ['/* testNamespaceNameIsString1 */'],
'namespace declaration (partial): class' => ['/* testNamespaceNameIsString2 */'],
'namespace declaration (partial): foreach' => ['/* testNamespaceNameIsString3 */'],
'function declaration: eval' => ['/* testKeywordAfterFunctionShouldBeString */'],
'function declaration with return by ref: switch' => ['/* testKeywordAfterFunctionByRefShouldBeString */'],
'function declaration with return by ref: static' => ['/* testKeywordStaticAfterFunctionByRefShouldBeString */'],
'function call: static' => ['/* testKeywordAsFunctionCallNameShouldBeStringStatic */'],
'method call: static' => ['/* testKeywordAsMethodCallNameShouldBeStringStatic */'],
'method call: static with dnf look a like param' => ['/* testKeywordAsFunctionCallNameShouldBeStringStaticDNFLookaLike */'],
];
}//end dataStrings()
/**
* Test that context sensitive keyword is tokenized as keyword when it should be keyword.
*
* @param string $testMarker The comment which prefaces the target token in the test file.
* @param string $expectedTokenType The expected token type.
*
* @dataProvider dataKeywords
* @covers PHP_CodeSniffer\Tokenizers\PHP::tokenize
*
* @return void
*/
public function testKeywords($testMarker, $expectedTokenType)
{
$tokenTargets = Tokens::$contextSensitiveKeywords;
$tokenTargets[] = T_STRING;
$tokenTargets[] = T_ANON_CLASS;
$tokenTargets[] = T_MATCH_DEFAULT;
$tokenTargets[] = T_PRIVATE_SET;
$tokenTargets[] = T_PROTECTED_SET;
$tokenTargets[] = T_PUBLIC_SET;
$tokens = $this->phpcsFile->getTokens();
$target = $this->getTargetToken($testMarker, $tokenTargets);
$tokenArray = $tokens[$target];
$this->assertSame(
constant($expectedTokenType),
$tokenArray['code'],
'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (code)'
);
$this->assertSame(
$expectedTokenType,
$tokenArray['type'],
'Token tokenized as '.$tokenArray['type'].', not '.$expectedTokenType.' (type)'
);
}//end testKeywords()
/**
* Data provider.
*
* @see testKeywords()
*
* @return array>
*/
public static function dataKeywords()
{
return [
'namespace: declaration' => [
'testMarker' => '/* testNamespaceIsKeyword */',
'expectedTokenType' => 'T_NAMESPACE',
],
'array: default value in const decl' => [
'testMarker' => '/* testArrayIsKeywordInConstDefault */',
'expectedTokenType' => 'T_ARRAY',
],
'static: type in constant declaration' => [
'testMarker' => '/* testStaticIsKeywordAsConstType */',
'expectedTokenType' => 'T_STATIC',
],
'static: value in constant declaration' => [
'testMarker' => '/* testStaticIsKeywordAsConstDefault */',
'expectedTokenType' => 'T_STATIC',
],
'abstract: class declaration' => [
'testMarker' => '/* testAbstractIsKeyword */',
'expectedTokenType' => 'T_ABSTRACT',
],
'class: declaration' => [
'testMarker' => '/* testClassIsKeyword */',
'expectedTokenType' => 'T_CLASS',
],
'extends: in class declaration' => [
'testMarker' => '/* testExtendsIsKeyword */',
'expectedTokenType' => 'T_EXTENDS',
],
'implements: in class declaration' => [
'testMarker' => '/* testImplementsIsKeyword */',
'expectedTokenType' => 'T_IMPLEMENTS',
],
'use: in trait import' => [
'testMarker' => '/* testUseIsKeyword */',
'expectedTokenType' => 'T_USE',
],
'insteadof: in trait import' => [
'testMarker' => '/* testInsteadOfIsKeyword */',
'expectedTokenType' => 'T_INSTEADOF',
],
'as: in trait import' => [
'testMarker' => '/* testAsIsKeyword */',
'expectedTokenType' => 'T_AS',
],
'const: declaration' => [
'testMarker' => '/* testConstIsKeyword */',
'expectedTokenType' => 'T_CONST',
],
'private: property declaration' => [
'testMarker' => '/* testPrivateIsKeyword */',
'expectedTokenType' => 'T_PRIVATE',
],
'protected: property declaration' => [
'testMarker' => '/* testProtectedIsKeyword */',
'expectedTokenType' => 'T_PROTECTED',
],
'public: property declaration' => [
'testMarker' => '/* testPublicIsKeyword */',
'expectedTokenType' => 'T_PUBLIC',
],
'private(set): property declaration' => [
'testMarker' => '/* testPrivateSetIsKeyword */',
'expectedTokenType' => 'T_PRIVATE_SET',
],
'protected(set): property declaration' => [
'testMarker' => '/* testProtectedSetIsKeyword */',
'expectedTokenType' => 'T_PROTECTED_SET',
],
'public(set): property declaration' => [
'testMarker' => '/* testPublicSetIsKeyword */',
'expectedTokenType' => 'T_PUBLIC_SET',
],
'var: property declaration' => [
'testMarker' => '/* testVarIsKeyword */',
'expectedTokenType' => 'T_VAR',
],
'static: property declaration' => [
'testMarker' => '/* testStaticIsKeyword */',
'expectedTokenType' => 'T_STATIC',
],
'readonly: property declaration' => [
'testMarker' => '/* testReadonlyIsKeywordForProperty */',
'expectedTokenType' => 'T_READONLY',
],
'final: function declaration' => [
'testMarker' => '/* testFinalIsKeyword */',
'expectedTokenType' => 'T_FINAL',
],
'function: declaration' => [
'testMarker' => '/* testFunctionIsKeyword */',
'expectedTokenType' => 'T_FUNCTION',
],
'callable: param type declaration' => [
'testMarker' => '/* testCallableIsKeyword */',
'expectedTokenType' => 'T_CALLABLE',
],
'readonly: anon class declaration' => [
'testMarker' => '/* testReadonlyIsKeywordForAnonClass */',
'expectedTokenType' => 'T_READONLY',
],
'return: statement' => [
'testMarker' => '/* testReturnIsKeyword */',
'expectedTokenType' => 'T_RETURN',
],
'interface: declaration' => [
'testMarker' => '/* testInterfaceIsKeyword */',
'expectedTokenType' => 'T_INTERFACE',
],
'trait: declaration' => [
'testMarker' => '/* testTraitIsKeyword */',
'expectedTokenType' => 'T_TRAIT',
],
'enum: declaration' => [
'testMarker' => '/* testEnumIsKeyword */',
'expectedTokenType' => 'T_ENUM',
],
'new: named instantiation' => [
'testMarker' => '/* testNewIsKeyword */',
'expectedTokenType' => 'T_NEW',
],
'instanceof: comparison' => [
'testMarker' => '/* testInstanceOfIsKeyword */',
'expectedTokenType' => 'T_INSTANCEOF',
],
'clone' => [
'testMarker' => '/* testCloneIsKeyword */',
'expectedTokenType' => 'T_CLONE',
],
'if' => [
'testMarker' => '/* testIfIsKeyword */',
'expectedTokenType' => 'T_IF',
],
'empty' => [
'testMarker' => '/* testEmptyIsKeyword */',
'expectedTokenType' => 'T_EMPTY',
],
'elseif' => [
'testMarker' => '/* testElseIfIsKeyword */',
'expectedTokenType' => 'T_ELSEIF',
],
'else' => [
'testMarker' => '/* testElseIsKeyword */',
'expectedTokenType' => 'T_ELSE',
],
'endif' => [
'testMarker' => '/* testEndIfIsKeyword */',
'expectedTokenType' => 'T_ENDIF',
],
'for' => [
'testMarker' => '/* testForIsKeyword */',
'expectedTokenType' => 'T_FOR',
],
'endfor' => [
'testMarker' => '/* testEndForIsKeyword */',
'expectedTokenType' => 'T_ENDFOR',
],
'foreach' => [
'testMarker' => '/* testForeachIsKeyword */',
'expectedTokenType' => 'T_FOREACH',
],
'endforeach' => [
'testMarker' => '/* testEndForeachIsKeyword */',
'expectedTokenType' => 'T_ENDFOREACH',
],
'switch' => [
'testMarker' => '/* testSwitchIsKeyword */',
'expectedTokenType' => 'T_SWITCH',
],
'case: in switch' => [
'testMarker' => '/* testCaseIsKeyword */',
'expectedTokenType' => 'T_CASE',
],
'default: in switch' => [
'testMarker' => '/* testDefaultIsKeyword */',
'expectedTokenType' => 'T_DEFAULT',
],
'endswitch' => [
'testMarker' => '/* testEndSwitchIsKeyword */',
'expectedTokenType' => 'T_ENDSWITCH',
],
'break: in switch' => [
'testMarker' => '/* testBreakIsKeyword */',
'expectedTokenType' => 'T_BREAK',
],
'continue: in switch' => [
'testMarker' => '/* testContinueIsKeyword */',
'expectedTokenType' => 'T_CONTINUE',
],
'do' => [
'testMarker' => '/* testDoIsKeyword */',
'expectedTokenType' => 'T_DO',
],
'while' => [
'testMarker' => '/* testWhileIsKeyword */',
'expectedTokenType' => 'T_WHILE',
],
'endwhile' => [
'testMarker' => '/* testEndWhileIsKeyword */',
'expectedTokenType' => 'T_ENDWHILE',
],
'try' => [
'testMarker' => '/* testTryIsKeyword */',
'expectedTokenType' => 'T_TRY',
],
'throw: statement' => [
'testMarker' => '/* testThrowIsKeyword */',
'expectedTokenType' => 'T_THROW',
],
'catch' => [
'testMarker' => '/* testCatchIsKeyword */',
'expectedTokenType' => 'T_CATCH',
],
'finally' => [
'testMarker' => '/* testFinallyIsKeyword */',
'expectedTokenType' => 'T_FINALLY',
],
'global' => [
'testMarker' => '/* testGlobalIsKeyword */',
'expectedTokenType' => 'T_GLOBAL',
],
'echo' => [
'testMarker' => '/* testEchoIsKeyword */',
'expectedTokenType' => 'T_ECHO',
],
'print: statement' => [
'testMarker' => '/* testPrintIsKeyword */',
'expectedTokenType' => 'T_PRINT',
],
'die: statement' => [
'testMarker' => '/* testDieIsKeyword */',
'expectedTokenType' => 'T_EXIT',
],
'eval' => [
'testMarker' => '/* testEvalIsKeyword */',
'expectedTokenType' => 'T_EVAL',
],
'exit: statement' => [
'testMarker' => '/* testExitIsKeyword */',
'expectedTokenType' => 'T_EXIT',
],
'isset' => [
'testMarker' => '/* testIssetIsKeyword */',
'expectedTokenType' => 'T_ISSET',
],
'unset' => [
'testMarker' => '/* testUnsetIsKeyword */',
'expectedTokenType' => 'T_UNSET',
],
'\\die: statement (fully qualified)' => [
'testMarker' => '/* testFullyQualifiedDieIsKeyword */',
'expectedTokenType' => 'T_EXIT',
],
'\\exit: statement (fully qualified)' => [
'testMarker' => '/* testFullyQualifiedExitIsKeyword */',
'expectedTokenType' => 'T_EXIT',
],
'include' => [
'testMarker' => '/* testIncludeIsKeyword */',
'expectedTokenType' => 'T_INCLUDE',
],
'include_once' => [
'testMarker' => '/* testIncludeOnceIsKeyword */',
'expectedTokenType' => 'T_INCLUDE_ONCE',
],
'require' => [
'testMarker' => '/* testRequireIsKeyword */',
'expectedTokenType' => 'T_REQUIRE',
],
'require_once' => [
'testMarker' => '/* testRequireOnceIsKeyword */',
'expectedTokenType' => 'T_REQUIRE_ONCE',
],
'list' => [
'testMarker' => '/* testListIsKeyword */',
'expectedTokenType' => 'T_LIST',
],
'goto' => [
'testMarker' => '/* testGotoIsKeyword */',
'expectedTokenType' => 'T_GOTO',
],
'match' => [
'testMarker' => '/* testMatchIsKeyword */',
'expectedTokenType' => 'T_MATCH',
],
'default: in match expression' => [
'testMarker' => '/* testMatchDefaultIsKeyword */',
'expectedTokenType' => 'T_MATCH_DEFAULT',
],
'fn' => [
'testMarker' => '/* testFnIsKeyword */',
'expectedTokenType' => 'T_FN',
],
'yield' => [
'testMarker' => '/* testYieldIsKeyword */',
'expectedTokenType' => 'T_YIELD',
],
'yield from' => [
'testMarker' => '/* testYieldFromIsKeyword */',
'expectedTokenType' => 'T_YIELD_FROM',
],
'declare' => [
'testMarker' => '/* testDeclareIsKeyword */',
'expectedTokenType' => 'T_DECLARE',
],
'enddeclare' => [
'testMarker' => '/* testEndDeclareIsKeyword */',
'expectedTokenType' => 'T_ENDDECLARE',
],
'and: in if' => [
'testMarker' => '/* testAndIsKeyword */',
'expectedTokenType' => 'T_LOGICAL_AND',
],
'or: in if' => [
'testMarker' => '/* testOrIsKeyword */',
'expectedTokenType' => 'T_LOGICAL_OR',
],
'xor: in if' => [
'testMarker' => '/* testXorIsKeyword */',
'expectedTokenType' => 'T_LOGICAL_XOR',
],
'class: anon class declaration' => [
'testMarker' => '/* testAnonymousClassIsKeyword */',
'expectedTokenType' => 'T_ANON_CLASS',
],
'extends: anon class declaration' => [
'testMarker' => '/* testExtendsInAnonymousClassIsKeyword */',
'expectedTokenType' => 'T_EXTENDS',
],
'implements: anon class declaration' => [
'testMarker' => '/* testImplementsInAnonymousClassIsKeyword */',
'expectedTokenType' => 'T_IMPLEMENTS',
],
'static: class instantiation' => [
'testMarker' => '/* testClassInstantiationStaticIsKeyword */',
'expectedTokenType' => 'T_STATIC',
],
'namespace: operator' => [
'testMarker' => '/* testNamespaceInNameIsKeyword */',
'expectedTokenType' => 'T_NAMESPACE',
],
'static: closure declaration' => [
'testMarker' => '/* testStaticIsKeywordBeforeClosure */',
'expectedTokenType' => 'T_STATIC',
],
'static: parameter type (illegal)' => [
'testMarker' => '/* testStaticIsKeywordWhenParamType */',
'expectedTokenType' => 'T_STATIC',
],
'static: arrow function declaration' => [
'testMarker' => '/* testStaticIsKeywordBeforeArrow */',
'expectedTokenType' => 'T_STATIC',
],
'static: return type for arrow function' => [
'testMarker' => '/* testStaticIsKeywordWhenReturnType */',
'expectedTokenType' => 'T_STATIC',
],
'static: property modifier before DNF' => [
'testMarker' => '/* testStaticIsKeywordPropertyModifierBeforeDNF */',
'expectedTokenType' => 'T_STATIC',
],
];
}//end dataKeywords()
}//end class