diff --git a/.gitattributes b/.gitattributes index 63babab..3f3d483 100644 --- a/.gitattributes +++ b/.gitattributes @@ -10,6 +10,7 @@ /.gitignore export-ignore /.gitmodules export-ignore /.npmrc export-ignore +/.phan export-ignore /.travis.yml export-ignore /appveyor.yml export-ignore /codecov.yml export-ignore diff --git a/.phan/config.php b/.phan/config.php new file mode 100644 index 0000000..a3beb49 --- /dev/null +++ b/.phan/config.php @@ -0,0 +1,308 @@ + '7.0', + + // If enabled, missing properties will be created when + // they are first seen. If false, we'll report an + // error message if there is an attempt to write + // to a class property that wasn't explicitly + // defined. + 'allow_missing_properties' => false, + + // If enabled, null can be cast as any type and any + // type can be cast to null. Setting this to true + // will cut down on false positives. + 'null_casts_as_any_type' => false, + + // If enabled, allow null to be cast as any array-like type. + // This is an incremental step in migrating away from null_casts_as_any_type. + // If null_casts_as_any_type is true, this has no effect. + 'null_casts_as_array' => false, + + // If enabled, allow any array-like type to be cast to null. + // This is an incremental step in migrating away from null_casts_as_any_type. + // If null_casts_as_any_type is true, this has no effect. + 'array_casts_as_null' => false, + + // If enabled, scalars (int, float, bool, string, null) + // are treated as if they can cast to each other. + // This does not affect checks of array keys. See scalar_array_key_cast. + 'scalar_implicit_cast' => false, + + // If enabled, any scalar array keys (int, string) + // are treated as if they can cast to each other. + // E.g. array can cast to array and vice versa. + // Normally, a scalar type such as int could only cast to/from int and mixed. + 'scalar_array_key_cast' => false, + + // If this has entries, scalars (int, float, bool, string, null) + // are allowed to perform the casts listed. + // E.g. ['int' => ['float', 'string'], 'float' => ['int'], 'string' => ['int'], 'null' => ['string']] + // allows casting null to a string, but not vice versa. + // (subset of scalar_implicit_cast) + 'scalar_implicit_partial' => [], + + // If true, seemingly undeclared variables in the global + // scope will be ignored. This is useful for projects + // with complicated cross-file globals that you have no + // hope of fixing. + 'ignore_undeclared_variables_in_global_scope' => false, + + // Backwards Compatibility Checking. This is slow + // and expensive, but you should consider running + // it before upgrading your version of PHP to a + // new version that has backward compatibility + // breaks. + 'backward_compatibility_checks' => false, + + // If true, check to make sure the return type declared + // in the doc-block (if any) matches the return type + // declared in the method signature. + 'check_docblock_signature_return_type_match' => true, + + // (*Requires check_docblock_signature_param_type_match to be true*) + // If true, make narrowed types from phpdoc params override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // Affects analysis of the body of the method and the param types passed in by callers. + 'prefer_narrowed_phpdoc_param_type' => true, + + // (*Requires check_docblock_signature_return_type_match to be true*) + // If true, make narrowed types from phpdoc returns override + // the real types from the signature, when real types exist. + // (E.g. allows specifying desired lists of subclasses, + // or to indicate a preference for non-nullable types over nullable types) + // Affects analysis of return statements in the body of the method and the return types passed in by callers. + 'prefer_narrowed_phpdoc_return_type' => true, + + 'ensure_signature_compatibility' => true, + + // Set to true in order to attempt to detect dead + // (unreferenced) code. Keep in mind that the + // results will only be a guess given that classes, + // properties, constants and methods can be referenced + // as variables (like `$class->$property` or + // `$class->$method()`) in ways that we're unable + // to make sense of. + 'dead_code_detection' => false, + + // If true, this run a quick version of checks that takes less + // time at the cost of not running as thorough + // an analysis. You should consider setting this + // to true only when you wish you had more **undiagnosed** issues + // to fix in your code base. + // + // In quick-mode the scanner doesn't rescan a function + // or a method's code block every time a call is seen. + // This means that the problem here won't be detected: + // + // ```php + // false, + + // If true, then before analysis, try to simplify AST into a form + // which improves Phan's type inference in edge cases. + // + // This may conflict with 'dead_code_detection'. + // When this is true, this slows down analysis slightly. + // + // E.g. rewrites `if ($a = value() && $a > 0) {...}` + // into $a = value(); if ($a) { if ($a > 0) {...}}` + 'simplify_ast' => true, + + // Enable or disable support for generic templated + // class types. + 'generic_types_enabled' => true, + + // Override to hardcode existence and types of (non-builtin) globals in the global scope. + // Class names should be prefixed with '\\'. + // (E.g. ['_FOO' => '\\FooClass', 'page' => '\\PageClass', 'userId' => 'int']) + 'globals_type_map' => [], + + // The minimum severity level to report on. This can be + // set to Issue::SEVERITY_LOW, Issue::SEVERITY_NORMAL or + // Issue::SEVERITY_CRITICAL. Setting it to only + // critical issues is a good place to start on a big + // sloppy mature code base. + 'minimum_severity' => Issue::SEVERITY_LOW, + + // Add any issue types (such as 'PhanUndeclaredMethod') + // to this black-list to inhibit them from being reported. + 'suppress_issue_types' => [ + 'PhanTypeMismatchDeclaredParamNullable', + 'PhanUndeclaredProperty', // 66 occurence(s) (e.g. not being specific enough about the subclass) + 'PhanUndeclaredMethod', // 32 occurence(s) (e.g. not being specific enough about the subclass of Node) + 'PhanTypeMismatchArgument', // 21 occurence(s) + 'PhanTypeMismatchProperty', // 13 occurence(s) + 'PhanUnreferencedUseNormal', // 10 occurence(s) TODO: Fix + 'PhanTypeMismatchDeclaredReturn', // 8 occurence(s) + 'PhanUndeclaredTypeProperty', // 7 occurence(s) + 'PhanTypeMismatchReturn', // 6 occurence(s) + 'PhanUndeclaredVariable', // 4 occurence(s) + 'PhanUndeclaredTypeReturnType', // 4 occurence(s) + 'PhanParamTooMany', // 3 occurence(s) + 'PhanUndeclaredTypeParameter', // 2 occurence(s) + 'PhanUndeclaredClassProperty', // 2 occurence(s) + 'PhanTypeSuspiciousStringExpression', // 2 occurence(s) + 'PhanTypeMismatchArgumentInternal', // 2 occurence(s) + 'PhanUnextractableAnnotationElementName', // 1 occurence(s) + 'PhanUndeclaredClassMethod', // 1 occurence(s) + 'PhanUndeclaredClassInstanceof', // 1 occurence(s) + 'PhanTypeSuspiciousNonTraversableForeach', // 1 occurence(s) + 'PhanTypeMismatchDimAssignment', // 1 occurence(s) + 'PhanTypeMismatchDeclaredParam', // 1 occurence(s) + 'PhanTypeInvalidDimOffset', // 1 occurence(s) + ], + + // A regular expression to match files to be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding groups of test or example + // directories/files, unanalyzable files, or files that + // can't be removed for whatever reason. + // (e.g. '@Test\.php$@', or '@vendor/.*/(tests|Tests)/@') + 'exclude_file_regex' => '@^vendor/.*/(tests?|Tests?)/@', + + // A file list that defines files that will be excluded + // from parsing and analysis and will not be read at all. + // + // This is useful for excluding hopelessly unanalyzable + // files that can't be removed for whatever reason. + 'exclude_file_list' => [], + + // A directory list that defines files that will be excluded + // from static analysis, but whose class and method + // information should be included. + // + // Generally, you'll want to include the directories for + // third-party code (such as "vendor/") in this list. + // + // n.b.: If you'd like to parse but not analyze 3rd + // party code, directories containing that code + // should be added to the `directory_list` as + // to `excluce_analysis_directory_list`. + 'exclude_analysis_directory_list' => [ + 'vendor/', + ], + + // The number of processes to fork off during the analysis + // phase. + 'processes' => 1, + + // List of case-insensitive file extensions supported by Phan. + // (e.g. php, html, htm) + 'analyzed_file_extensions' => [ + 'php', + ], + + // You can put paths to stubs of internal extensions in this config option. + // If the corresponding extension is **not** loaded, then phan will use the stubs instead. + // Phan will continue using its detailed type annotations, + // but load the constants, classes, functions, and classes (and their Reflection types) + // from these stub files (doubling as valid php files). + // Use a different extension from php to avoid accidentally loading these. + // The 'tools/make_stubs' script can be used to generate your own stubs (compatible with php 7.0+ right now) + 'autoload_internal_extension_signatures' => [], + + // A list of plugin files to execute + // Plugins which are bundled with Phan can be added here by providing their name (e.g. 'AlwaysReturnPlugin') + // Alternately, you can pass in the full path to a PHP file with the plugin's implementation (e.g. 'vendor/phan/phan/.phan/plugins/AlwaysReturnPlugin.php') + 'plugins' => [ + 'AlwaysReturnPlugin', + 'DollarDollarPlugin', + 'DuplicateArrayKeyPlugin', + 'PregRegexCheckerPlugin', + 'PrintfCheckerPlugin', + 'UnreachableCodePlugin', + ], + + // A list of directories that should be parsed for class and + // method information. After excluding the directories + // defined in exclude_analysis_directory_list, the remaining + // files will be statically analyzed for errors. + // + // Thus, both first-party and third-party code being used by + // your application should be included in this list. + 'directory_list' => [ + 'src', + 'vendor/composer/xdebug-handler/src', + 'vendor/felixfbecker/advanced-json-rpc/lib', + 'vendor/felixfbecker/language-server-protocol/src/', + 'vendor/microsoft/tolerant-php-parser/src', + 'vendor/netresearch/jsonmapper/src', + 'vendor/phpdocumentor/reflection-common/src', + 'vendor/phpdocumentor/reflection-docblock/src', + 'vendor/phpdocumentor/type-resolver/src', + 'vendor/phpunit/phpunit/src', + 'vendor/psr/log/Psr', + 'vendor/sabre/event/lib', + 'vendor/sabre/uri/lib', + 'vendor/webmozart/glob/src', + 'vendor/webmozart/path-util/src', + ], + + // A list of individual files to include in analysis + // with a path relative to the root directory of the + // project + 'file_list' => [ + 'bin/php-language-server.php', + ], +]; diff --git a/.travis.yml b/.travis.yml index 3d03dcf..da1f118 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,8 +16,11 @@ cache: install: - composer install --prefer-dist --no-interaction + - pecl install ast-1.0.0 + script: - vendor/bin/phpcs -n + - vendor/bin/phan - vendor/bin/phpunit --coverage-clover=coverage.xml --colors=always - bash <(curl -s https://codecov.io/bash) diff --git a/composer.json b/composer.json index ffa5971..f63bf3a 100644 --- a/composer.json +++ b/composer.json @@ -37,6 +37,7 @@ }, "require-dev": { "phpunit/phpunit": "^6.3", + "phan/phan": "1.1.4", "squizlabs/php_codesniffer": "^3.1" }, "autoload": {