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');