diff --git a/docs/README.md b/docs/README.md index 976803884..01072669c 100644 --- a/docs/README.md +++ b/docs/README.md @@ -14,7 +14,7 @@ It has a few features that go further than other similar tools: Psalm checks that all properties of a given object have values after the constructor is called. - **Support for complicated array shapes**
- Psalm has support for [object-like arrays](docblock_type_syntax.md#object-like-arrays), allowing you to specify types for all keys of an array if you so wish. + Psalm has support for [object-like arrays](annotating_code/docblock_type_syntax.md#object-like-arrays), allowing you to specify types for all keys of an array if you so wish. Psalm also has a few features to make it perform as well as possible on large codebases: @@ -48,22 +48,24 @@ There are two main inspirations for Psalm: ## Index - Running Psalm: - - [Installation](installation.md) - - [Configuration](configuration.md) + - [Installation](running_psalm/installation.md) + - [Configuration](running_psalm/configuration.md) - Plugins - - [Using plugins](using_plugins.md) - - [Authoring plugins](authoring_plugins.md) - - [How Psalm represents types](plugins_type_system.md) - - [Command line usage](running_psalm.md) - - [IDE support](language_server.md) + - [Using plugins](running_psalm/plugins/using_plugins.md) + - [Authoring plugins](running_psalm/plugins/authoring_plugins.md) + - [How Psalm represents types](running_psalm/plugins/plugins_type_system.md) + - [Command line usage](running_psalm/command_line_usage.md) + - [IDE support](running_psalm/language_server.md) - Handling errors: - - [Dealing with code issues](dealing_with_code_issues.md) - - [Issue Types](issues.md) - - [Checking non-PHP files](checking_non_php_files.md) + - [Dealing with code issues](running_psalm/dealing_with_code_issues.md) + - [Issue Types](running_psalm/issues.md) + - [Checking non-PHP files](running_psalm/checking_non_php_files.md) - Annotating code: - - [Typing in Psalm](typing_in_psalm.md) - - [Docblock Type Syntax](docblock_type_syntax.md) - - [Supported Annotations](supported_annotations.md) - - [Template Annotations](templated_annotations.md) - - [Fixing code](fixing_code.md) + - [Typing in Psalm](annotating_code/typing_in_psalm.md) + - [Docblock Type Syntax](annotating_code/docblock_type_syntax.md) + - [Supported Annotations](annotating_code/supported_annotations.md) + - [Template Annotations](annotating_code/templated_annotations.md) +- Manipulating code: + - [Fixing code](manipulating_code/fixing_code.md) + - [Refactoring code](manipulating_code/refactoring_code.md) diff --git a/docs/docblock_type_syntax.md b/docs/annotating_code/docblock_type_syntax.md similarity index 97% rename from docs/docblock_type_syntax.md rename to docs/annotating_code/docblock_type_syntax.md index 98528d0f1..30b45fa6f 100644 --- a/docs/docblock_type_syntax.md +++ b/docs/annotating_code/docblock_type_syntax.md @@ -35,7 +35,7 @@ class A {} function takesClassName(string $s) : void {} ``` -`takesClassName("A");` would trigger a `TypeCoercion` issue (or a `PossiblyInvalidArgument` issue if [`allowCoercionFromStringToClassConst`](configuration.md#coding-style) was set to `false` in your config), whereas `takesClassName(A::class)` is fine. +`takesClassName("A");` would trigger a `TypeCoercion` issue (or a `PossiblyInvalidArgument` issue if [`allowCoercionFromStringToClassConst`](../running_psalm/configuration.md#coding-style) was set to `false` in your config), whereas `takesClassName(A::class)` is fine. ### Object types diff --git a/docs/supported_annotations.md b/docs/annotating_code/supported_annotations.md similarity index 100% rename from docs/supported_annotations.md rename to docs/annotating_code/supported_annotations.md diff --git a/docs/templated_annotations.md b/docs/annotating_code/templated_annotations.md similarity index 100% rename from docs/templated_annotations.md rename to docs/annotating_code/templated_annotations.md diff --git a/docs/typing_in_psalm.md b/docs/annotating_code/typing_in_psalm.md similarity index 100% rename from docs/typing_in_psalm.md rename to docs/annotating_code/typing_in_psalm.md diff --git a/docs/fixing_code.md b/docs/manipulating_code/fixing_code.md similarity index 100% rename from docs/fixing_code.md rename to docs/manipulating_code/fixing_code.md diff --git a/docs/manipulating_code/refactoring_code.md b/docs/manipulating_code/refactoring_code.md new file mode 100644 index 000000000..66b87b01a --- /dev/null +++ b/docs/manipulating_code/refactoring_code.md @@ -0,0 +1,21 @@ +# Refactoring Code + +Sometimes you want to make big changes to your codebase like moving methods or classes. + +Psalm has a refactoring tool you can access with either `vendor/bin/psalm-refactor` or `vendor/bin/psalm --refactor`, followed by appropriate commands. + +## Moving classes between namespaces + +`vendor/bin/psalm-refactor --move "Ns1\Foo" --into "Ns2"` tells Psalm to move class `Ns1\Foo` into the namespace `Ns2`, so any reference to `Ns1\Foo` becomes `Ns2\Foo`). + +## Moving and renaming classes + +`vendor/bin/psalm-refactor --rename "Ns1\Foo" --to "Ns2\Bar\Baz"` tells Psalm to move class `Ns1\Foo` into the namespace `Ns2\Bar` and rename it to `Baz`, so any reference to `Ns1\Foo` becomes `Ns2\Bar\Baz`). + +## Moving methods between classes + +`vendor/bin/psalm-refactor --move "Ns1\Foo::bar" --into "Ns2\Baz"` tells Psalm to move a method named `bar` inside `Ns1\Foo` into the class `Ns2\Baz`, so any reference to `Ns1\Foo::bar` becomes `Ns2\Baz::bar`). Psalm currently allows you to move static methods between aribitrary classes, and instance methods into child classes of that instance. + +## Moving and renaming methods + +`vendor/bin/psalm-refactor --rename "Ns1\Foo::bar" --to "Ns2\Baz::bat"` tells Psalm to move method `Ns1\Foo::bar` into the class `Ns2\Baz` and rename it to `bat`, so any reference to `Ns1\Foo::bar` becomes `Ns2\Baz::bat`). diff --git a/docs/checking_non_php_files.md b/docs/running_psalm/checking_non_php_files.md similarity index 100% rename from docs/checking_non_php_files.md rename to docs/running_psalm/checking_non_php_files.md diff --git a/docs/running_psalm.md b/docs/running_psalm/command_line_usage.md similarity index 100% rename from docs/running_psalm.md rename to docs/running_psalm/command_line_usage.md diff --git a/docs/configuration.md b/docs/running_psalm/configuration.md similarity index 96% rename from docs/configuration.md rename to docs/running_psalm/configuration.md index 35a4914fc..580942bac 100644 --- a/docs/configuration.md +++ b/docs/running_psalm/configuration.md @@ -103,7 +103,7 @@ Allows you to specify whether or not to use the typed iterator docblock format s allowCoercionFromStringToClassConst="[bool]" > ``` -When `true`, strings can be coerced to [`class-string`](templated_annotations.md#param-class-stringt), with Psalm emitting a `TypeCoercion` issue. If disabled, that issue changes to a more serious one. Defaults to `false`. +When `true`, strings can be coerced to [`class-string`](../annotating_code/templated_annotations.md#param-class-stringt), with Psalm emitting a `TypeCoercion` issue. If disabled, that issue changes to a more serious one. Defaults to `false`. #### allowStringToStandInForClass @@ -243,7 +243,7 @@ Contains a list of all the directories that Psalm should inspect. You can also s Optional. A list of extensions to search over. See [Checking non-PHP files](checking_non_php_files.md) to understand how to extend this. #### `` -Optional. A list of `` entries. See the [Plugins](using_plugins.md) section for more information. +Optional. A list of `` entries. See the [Plugins](plugins/using_plugins.md) section for more information. #### `` Optional. If you don't want Psalm to complain about every single issue it finds, the issueHandler tag allows you to configure that. [Dealing with code issues](dealing_with_code_issues.md) tells you more. diff --git a/docs/dealing_with_code_issues.md b/docs/running_psalm/dealing_with_code_issues.md similarity index 100% rename from docs/dealing_with_code_issues.md rename to docs/running_psalm/dealing_with_code_issues.md diff --git a/docs/installation.md b/docs/running_psalm/installation.md similarity index 100% rename from docs/installation.md rename to docs/running_psalm/installation.md diff --git a/docs/issues.md b/docs/running_psalm/issues.md similarity index 100% rename from docs/issues.md rename to docs/running_psalm/issues.md diff --git a/docs/language_server.md b/docs/running_psalm/language_server.md similarity index 100% rename from docs/language_server.md rename to docs/running_psalm/language_server.md diff --git a/docs/authoring_plugins.md b/docs/running_psalm/plugins/authoring_plugins.md similarity index 95% rename from docs/authoring_plugins.md rename to docs/running_psalm/plugins/authoring_plugins.md index 297943725..e640cc1e6 100644 --- a/docs/authoring_plugins.md +++ b/docs/running_psalm/plugins/authoring_plugins.md @@ -36,7 +36,7 @@ Here are a couple of example plugins: - [PreventFloatAssignmentChecker](https://github.com/vimeo/psalm/blob/master/examples/plugins/PreventFloatAssignmentChecker.php) - prevents assignment to floats - [FunctionCasingChecker](https://github.com/vimeo/psalm/blob/master/examples/plugins/FunctionCasingChecker.php) - checks that your functions and methods are correctly-cased -To ensure your plugin runs when Psalm does, add it to your [config](configuration.md): +To ensure your plugin runs when Psalm does, add it to your [config](../configuration.md): ```xml @@ -56,9 +56,9 @@ Understand how Psalm handles types by [reading this guide](plugins_type_system.m ## Handling custom plugin issues -Plugins may sometimes need to emit their own issues (i.e. not emit one of the [existing issues](issues.md)). If this is the case, they can emit an issue that extends `Psalm\Issue\PluginIssue`. +Plugins may sometimes need to emit their own issues (i.e. not emit one of the [existing issues](../issues.md)). If this is the case, they can emit an issue that extends `Psalm\Issue\PluginIssue`. -To suppress a custom plugin issue in docblocks you can just use its issue name (e.g. `/** @psalm-suppress NoFloatAssignment */`, but to [suppress it in Psalm’s config](dealing_with_code_issues.md#config-suppression) you must use the pattern: +To suppress a custom plugin issue in docblocks you can just use its issue name (e.g. `/** @psalm-suppress NoFloatAssignment */`, but to [suppress it in Psalm’s config](../dealing_with_code_issues.md#config-suppression) you must use the pattern: ```xml diff --git a/docs/plugins_type_system.md b/docs/running_psalm/plugins/plugins_type_system.md similarity index 99% rename from docs/plugins_type_system.md rename to docs/running_psalm/plugins/plugins_type_system.md index 6accea1f9..98936113d 100644 --- a/docs/plugins_type_system.md +++ b/docs/running_psalm/plugins/plugins_type_system.md @@ -4,7 +4,7 @@ Psalm's type system represents the types of variables within a program using dif ## Union types -All type Psalm's type information you are likely to use will be wrapped in a [Union Type](docblock_type_syntax.md#union-types). +All type Psalm's type information you are likely to use will be wrapped in a [Union Type](../annotating_code/docblock_type_syntax.md#union-types). The `Union` class constructor takes an array of `Atomic` types, and can represent one or more of these types at a time. They correspond to a vertical bar in a doc comment. diff --git a/docs/using_plugins.md b/docs/running_psalm/plugins/using_plugins.md similarity index 100% rename from docs/using_plugins.md rename to docs/running_psalm/plugins/using_plugins.md diff --git a/src/psalm-refactor.php b/src/psalm-refactor.php index 75d025eaf..3df8fafa7 100644 --- a/src/psalm-refactor.php +++ b/src/psalm-refactor.php @@ -199,8 +199,14 @@ foreach ($args as $arg) { $last_arg_parts = preg_split('/, ?/', $last_arg); foreach ($last_arg_parts as $last_arg_part) { - list(, $identifier_name) = explode('::', $last_arg_part); - $to_refactor[$last_arg_part] = $arg . '::' . $identifier_name; + if (strpos($last_arg_part, '::')) { + list(, $identifier_name) = explode('::', $last_arg_part); + $to_refactor[$last_arg_part] = $arg . '::' . $identifier_name; + } else { + $namespace_parts = explode('\\', $last_arg_part); + $class_name = end($namespace_parts); + $to_refactor[$last_arg_part] = $arg . '\\' . $class_name; + } } } else { $to_refactor[$last_arg] = $arg; diff --git a/tests/DocumentationTest.php b/tests/DocumentationTest.php index 8091097dc..a476f7fa8 100644 --- a/tests/DocumentationTest.php +++ b/tests/DocumentationTest.php @@ -16,7 +16,7 @@ class DocumentationTest extends TestCase */ private static function getCodeBlocksFromDocs() { - $issue_file = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'docs' . DIRECTORY_SEPARATOR . 'issues.md'; + $issue_file = dirname(dirname(__FILE__)) . DIRECTORY_SEPARATOR . 'docs' . DIRECTORY_SEPARATOR . 'running_psalm' . DIRECTORY_SEPARATOR . 'issues.md'; if (!file_exists($issue_file)) { throw new \UnexpectedValueException('docs not found');