Browse Source

RuleSet rework

SpacePossum 4 years ago
parent
commit
1a19947752

+ 0 - 4
phpstan.neon

@@ -13,7 +13,6 @@ parameters:
     ignoreErrors:
         - '/^Return typehint of method PhpCsFixer\\Tests\\Test\\.+::createIsIdenticalStringConstraint\(\) has invalid type PHPUnit_Framework_Constraint_IsIdentical\.$/'
         - '/^Class (Symfony\\Contracts\\EventDispatcher\\Event|Symfony\\Component\\EventDispatcher\\Event) not found.$/'
-        - '/^(Access|Call) to an undefined (property|method) PhpCsFixer\\AccessibleObject\\AccessibleObject::.+$/'
         - '/^Constant T_NAME_(RELATIVE|FULLY_QUALIFIED|QUALIFIED) not found\.$/'
         -
             message: '/^Unsafe usage of new static\(\)\.$/'
@@ -47,7 +46,4 @@ parameters:
         -
             message: '/^Parameter #1 \$finder of method PhpCsFixer\\Config::setFinder\(\) expects iterable<string>, int given\.$/'
             path: tests/ConfigTest.php
-        -
-            message: '/^Unreachable statement - code above always terminates\.$/'
-            path: tests/AutoReview/DocumentationTest.php
     tipsOfTheDay: false

+ 46 - 10
src/Console/Command/DescribeCommand.php

@@ -28,7 +28,7 @@ use PhpCsFixer\FixerDefinition\FixerDefinition;
 use PhpCsFixer\FixerDefinition\VersionSpecificCodeSampleInterface;
 use PhpCsFixer\FixerFactory;
 use PhpCsFixer\Preg;
-use PhpCsFixer\RuleSet;
+use PhpCsFixer\RuleSet\RuleSets;
 use PhpCsFixer\StdinFileInfo;
 use PhpCsFixer\Tokenizer\Tokens;
 use PhpCsFixer\Utils;
@@ -317,18 +317,34 @@ final class DescribeCommand extends Command
             throw new DescribeNameNotFoundException($name, 'set');
         }
 
-        $ruleSet = new RuleSet([$name => true]);
-        $rules = $ruleSet->getRules();
-        ksort($rules);
-
+        $ruleSetDefinitions = RuleSets::getSetDefinitions();
         $fixers = $this->getFixers();
 
-        $output->writeln(sprintf('<info>Description of</info> %s <info>set.</info>', $name));
+        $output->writeln(sprintf('<info>Description of the</info> %s <info>set.</info>', $ruleSetDefinitions[$name]->getName()));
+
+        $output->writeln($this->replaceRstLinks($ruleSetDefinitions[$name]->getDescription()));
+
+        if ($ruleSetDefinitions[$name]->isRisky()) {
+            $output->writeln('This set contains <error>risky</error> rules.');
+        }
+
         $output->writeln('');
 
         $help = '';
 
-        foreach ($rules as $rule => $config) {
+        foreach ($ruleSetDefinitions[$name]->getRules() as $rule => $config) {
+            if ('@' === $rule[0]) {
+                $set = $ruleSetDefinitions[$rule];
+                $help .= sprintf(
+                    " * <info>%s</info>%s\n   | %s\n\n",
+                    $rule,
+                    $set->isRisky() ? ' <error>risky</error>' : '',
+                    $this->replaceRstLinks($set->getDescription())
+                );
+
+                continue;
+            }
+
             $fixer = $fixers[$rule];
 
             if (!$fixer instanceof DefinedFixerInterface) {
@@ -381,9 +397,7 @@ final class DescribeCommand extends Command
             return $this->setNames;
         }
 
-        $set = new RuleSet();
-        $this->setNames = $set->getSetDefinitionNames();
-        sort($this->setNames);
+        $this->setNames = RuleSets::getSetDefinitionNames();
 
         return $this->setNames;
     }
@@ -412,4 +426,26 @@ final class DescribeCommand extends Command
             }
         }
     }
+
+    /**
+     * @param string $content
+     *
+     * @return string
+     */
+    private function replaceRstLinks($content)
+    {
+        return Preg::replaceCallback(
+            '/(`[^<]+<[^>]+>`_)/',
+            static function (array $matches) {
+                return Preg::replaceCallback(
+                    '/`(.*)<(.*)>`_/',
+                    static function (array $matches) {
+                        return $matches[1].'('.$matches[2].')';
+                    },
+                    $matches[1]
+                );
+            },
+            $content
+        );
+    }
 }

+ 38 - 18
src/Console/Command/DocumentationCommand.php

@@ -12,9 +12,9 @@
 
 namespace PhpCsFixer\Console\Command;
 
-use PhpCsFixer\AbstractFixer;
 use PhpCsFixer\Documentation\DocumentationGenerator;
 use PhpCsFixer\FixerFactory;
+use PhpCsFixer\RuleSet\RuleSets;
 use Symfony\Component\Console\Command\Command;
 use Symfony\Component\Console\Input\InputInterface;
 use Symfony\Component\Console\Output\OutputInterface;
@@ -53,36 +53,56 @@ final class DocumentationCommand extends Command
     {
         $fixerFactory = new FixerFactory();
         $fixerFactory->registerBuiltInFixers();
-
-        /** @var AbstractFixer[] $fixers */
         $fixers = $fixerFactory->getFixers();
 
-        $paths = [
-            '_index' => $this->generator->getFixersDocumentationIndexFilePath(),
-        ];
+        $this->generateFixersDocs($fixers);
+        $this->generateRuleSetsDocs($fixers);
 
+        return 0;
+    }
+
+    private function generateFixersDocs(array $fixers)
+    {
         $filesystem = new Filesystem();
 
+        /** @var SplFileInfo $file */
+        foreach ((new Finder())->files()->in($this->generator->getFixersDocumentationDirectoryPath()) as $file) {
+            $filesystem->remove($file->getPathname());
+        }
+
         foreach ($fixers as $fixer) {
-            $class = \get_class($fixer);
-            $paths[$class] = $path = $this->generator->getFixerDocumentationFilePath($fixer);
+            $filesystem->dumpFile(
+                $this->generator->getFixerDocumentationFilePath($fixer),
+                $this->generator->generateFixerDocumentation($fixer)
+            );
+        }
 
-            $filesystem->dumpFile($path, $this->generator->generateFixerDocumentation($fixer));
+        $index = $this->generator->getFixersDocumentationIndexFilePath();
+
+        if (false === @file_put_contents($index, $this->generator->generateFixersDocumentationIndex($fixers))) {
+            throw new \RuntimeException("Failed updating file {$index}.");
         }
+    }
 
-        /** @var SplFileInfo $file */
-        foreach ((new Finder())->files()->in($this->generator->getFixersDocumentationDirectoryPath()) as $file) {
-            $path = $file->getPathname();
+    private function generateRuleSetsDocs(array $fixers)
+    {
+        $filesystem = new Filesystem();
 
-            if (!\in_array($path, $paths, true)) {
-                $filesystem->remove($path);
-            }
+        /** @var SplFileInfo $file */
+        foreach ((new Finder())->files()->in($this->generator->getRuleSetsDocumentationDirectoryPath()) as $file) {
+            $filesystem->remove($file->getPathname());
         }
 
-        if (false === @file_put_contents($paths['_index'], $this->generator->generateFixersDocumentationIndex($fixers))) {
-            throw new \RuntimeException("Failed updating file {$paths['_index']}.");
+        $index = $this->generator->getRuleSetsDocumentationIndexFilePath();
+        $paths = [];
+
+        foreach (RuleSets::getSetDefinitions() as $name => $definition) {
+            $paths[$name] = $path = $this->generator->getRuleSetsDocumentationFilePath($name);
+            $filesystem->dumpFile($path, $this->generator->generateRuleSetsDocumentation($definition, $fixers));
         }
 
-        return 0;
+        if (false === @file_put_contents($index, $this->generator->generateRuleSetsDocumentationIndex($paths))) {
+            throw new \RuntimeException("Failed updating file {$index}.");
+        }
     }
 }

+ 18 - 11
src/Console/Command/HelpCommand.php

@@ -24,7 +24,8 @@ use PhpCsFixer\FixerConfiguration\DeprecatedFixerOption;
 use PhpCsFixer\FixerConfiguration\FixerOptionInterface;
 use PhpCsFixer\FixerFactory;
 use PhpCsFixer\Preg;
-use PhpCsFixer\RuleSet;
+use PhpCsFixer\RuleSet\RuleSet;
+use PhpCsFixer\RuleSet\RuleSets;
 use PhpCsFixer\Utils;
 use Symfony\Component\Console\Command\HelpCommand as BaseHelpCommand;
 use Symfony\Component\Console\Formatter\OutputFormatter;
@@ -186,7 +187,9 @@ The example below will add two rules to the default list of PSR2 set rules:
         ->in(__DIR__)
     ;
 
-    return PhpCsFixer\Config::create()
+    $config = new Config();
+
+    return $config
         ->setRules([
             '@PSR2' => true,
             'strict_param' => true,
@@ -213,7 +216,9 @@ The following example shows how to use all `Symfony` rules but the `full_opening
         ->in(__DIR__)
     ;
 
-    return PhpCsFixer\Config::create()
+    $config = new Config();
+
+    return $config
         ->setRules([
             '@Symfony' => true,
             'full_opening_tag' => false,
@@ -228,7 +233,9 @@ configure them in your config file.
 
     <?php
 
-    return PhpCsFixer\Config::create()
+    $config = new Config();
+
+    return $config
         ->setIndent("\t")
         ->setLineEnding("\r\n")
     ;
@@ -251,9 +258,9 @@ Cache can be disabled via `--using-cache` option or config file:
 
     <?php
 
-    return PhpCsFixer\Config::create()
-        ->setUsingCache(false)
-    ;
+    $config = new Config();
+
+    return $config->setUsingCache(false);
 
     ?>
 
@@ -261,9 +268,9 @@ Cache file can be specified via `--cache-file` option or config file:
 
     <?php
 
-    return PhpCsFixer\Config::create()
-        ->setCacheFile(__DIR__.'/.php_cs.cache')
-    ;
+    $config = new Config();
+
+    return $config->setCacheFile(__DIR__.'/.php_cs.cache');
 
     ?>
 
@@ -442,7 +449,7 @@ EOF
         );
 
         $ruleSets = [];
-        foreach (RuleSet::create()->getSetDefinitionNames() as $setName) {
+        foreach (RuleSets::getSetDefinitionNames() as $setName) {
             $ruleSets[$setName] = new RuleSet([$setName => true]);
         }
 

+ 1 - 1
src/Console/ConfigurationResolver.php

@@ -33,7 +33,7 @@ use PhpCsFixer\Linter\Linter;
 use PhpCsFixer\Linter\LinterInterface;
 use PhpCsFixer\Report\ReporterFactory;
 use PhpCsFixer\Report\ReporterInterface;
-use PhpCsFixer\RuleSet;
+use PhpCsFixer\RuleSet\RuleSet;
 use PhpCsFixer\StdinFileInfo;
 use PhpCsFixer\ToolInfoInterface;
 use PhpCsFixer\Utils;

+ 127 - 8
src/Documentation/DocumentationGenerator.php

@@ -29,7 +29,9 @@ use PhpCsFixer\FixerDefinition\CodeSampleInterface;
 use PhpCsFixer\FixerDefinition\FileSpecificCodeSampleInterface;
 use PhpCsFixer\FixerDefinition\VersionSpecificCodeSampleInterface;
 use PhpCsFixer\Preg;
-use PhpCsFixer\RuleSet;
+use PhpCsFixer\RuleSet\RuleSet;
+use PhpCsFixer\RuleSet\RuleSetDescriptionInterface;
+use PhpCsFixer\RuleSet\RuleSets;
 use PhpCsFixer\StdinFileInfo;
 use PhpCsFixer\Tokenizer\Tokens;
 use PhpCsFixer\Utils;
@@ -53,7 +55,7 @@ final class DocumentationGenerator
             'toFile' => 'New',
         ]));
 
-        $this->path = \dirname(__DIR__, 2).'/doc/rules';
+        $this->path = \dirname(__DIR__, 2).'/doc';
     }
 
     /**
@@ -61,7 +63,7 @@ final class DocumentationGenerator
      */
     public function getFixersDocumentationDirectoryPath()
     {
-        return $this->path;
+        return $this->path.'/rules';
     }
 
     /**
@@ -69,7 +71,7 @@ final class DocumentationGenerator
      */
     public function getFixersDocumentationIndexFilePath()
     {
-        return "{$this->path}/index.rst";
+        return $this->getFixersDocumentationDirectoryPath().'/index.rst';
     }
 
     /**
@@ -128,7 +130,7 @@ RST;
             }
 
             $path = Preg::replace(
-                '#^'.preg_quote($this->path, '#').'/#',
+                '#^'.preg_quote($this->getFixersDocumentationDirectoryPath(), '#').'/#',
                 './',
                 $this->getFixerDocumentationFilePath($fixer)
             );
@@ -148,7 +150,7 @@ RST;
      */
     public function getFixerDocumentationFilePath(FixerInterface $fixer)
     {
-        return $this->path.'/'.Preg::replaceCallback(
+        return $this->getFixersDocumentationDirectoryPath().'/'.Preg::replaceCallback(
             '/^.*\\\\(.+)\\\\(.+)Fixer$/',
             function (array $matches) {
                 return Utils::camelCaseToUnderscore($matches[1]).'/'.Utils::camelCaseToUnderscore($matches[2]);
@@ -308,7 +310,7 @@ RST;
 
         $ruleSetConfigs = [];
 
-        foreach ((new RuleSet())->getSetDefinitionNames() as $set) {
+        foreach (RuleSets::getSetDefinitionNames() as $set) {
             $ruleSet = new RuleSet([$set => true]);
 
             if ($ruleSet->hasRule($name)) {
@@ -328,11 +330,14 @@ The rule is part of the following rule set{$plural}:
 RST;
 
             foreach ($ruleSetConfigs as $set => $config) {
+                $ruleSetPath = $this->getRuleSetsDocumentationFilePath($set);
+                $ruleSetPath = substr($ruleSetPath, strrpos($ruleSetPath, '/'));
+
                 $doc .= <<<RST
 
 
 {$set}
-  Using the ``{$set}`` rule set will enable the ``{$name}`` rule
+  Using the `{$set} <./../../ruleSets{$ruleSetPath}>`_ rule set will enable the ``{$name}`` rule
 RST;
 
                 if (null !== $config) {
@@ -348,6 +353,108 @@ RST;
         return "{$doc}\n";
     }
 
+    /**
+     * @return string
+     */
+    public function getRuleSetsDocumentationDirectoryPath()
+    {
+        return $this->path.'/ruleSets';
+    }
+
+    /**
+     * @return string
+     */
+    public function getRuleSetsDocumentationIndexFilePath()
+    {
+        return $this->getRuleSetsDocumentationDirectoryPath().'/index.rst';
+    }
+
+    /**
+     * @param AbstractFixer[] $fixers
+     *
+     * @return string
+     */
+    public function generateRuleSetsDocumentation(RuleSetDescriptionInterface $definition, array $fixers)
+    {
+        $fixerNames = [];
+        foreach ($fixers as $fixer) {
+            $fixerNames[$fixer->getName()] = $fixer;
+        }
+
+        $title = "Rule set ``{$definition->getName()}``";
+        $titleLine = str_repeat('=', \strlen($title));
+        $doc = "{$titleLine}\n{$title}\n{$titleLine}\n\n".$definition->getDescription();
+        if ($definition->isRisky()) {
+            $doc .= ' This set contains rules that are risky.';
+        }
+        $doc .= "\n\n";
+
+        $rules = $definition->getRules();
+
+        if (\count($rules) < 1) {
+            $doc .= 'This is an empty set.';
+        } else {
+            $doc .= "Rules\n-----\n";
+
+            foreach ($rules as $rule => $config) {
+                if ('@' === $rule[0]) {
+                    $ruleSetPath = $this->getRuleSetsDocumentationFilePath($rule);
+                    $ruleSetPath = substr($ruleSetPath, strrpos($ruleSetPath, '/'));
+
+                    $doc .= "\n- `{$rule} <.{$ruleSetPath}>`_";
+                } else {
+                    $path = Preg::replace(
+                        '#^'.preg_quote($this->getFixersDocumentationDirectoryPath(), '#').'/#',
+                        './../rules/',
+                        $this->getFixerDocumentationFilePath($fixerNames[$rule])
+                    );
+
+                    $doc .= "\n- `{$rule} <{$path}>`_";
+                }
+
+                if (!\is_bool($config)) {
+                    $doc .= "\n  config:\n  ``".HelpCommand::toString($config).'``';
+                }
+            }
+        }
+
+        return $doc."\n";
+    }
+
+    /**
+     * @param string $name
+     *
+     * @return string
+     */
+    public function getRuleSetsDocumentationFilePath($name)
+    {
+        return $this->getRuleSetsDocumentationDirectoryPath().'/'.str_replace(':risky', 'Risky', ucfirst(substr($name, 1))).'.rst';
+    }
+
+    /**
+     * @return string
+     */
+    public function generateRuleSetsDocumentationIndex(array $setDefinitions)
+    {
+        $documentation = <<<'RST'
+===========================
+List of Available Rule sets
+===========================
+RST;
+        foreach ($setDefinitions as $name => $path) {
+            $path = substr($path, strrpos($path, '/'));
+            $documentation .= "\n- `{$name} <.{$path}>`_";
+        }
+
+        return $documentation."\n";
+    }
+
+    /**
+     * @param int    $sampleIndex
+     * @param string $ruleName
+     *
+     * @return string
+     */
     private function generateSampleDiff(FixerInterface $fixer, CodeSampleInterface $sample, $sampleIndex, $ruleName)
     {
         if ($sample instanceof VersionSpecificCodeSampleInterface && !$sample->isSuitableFor(\PHP_VERSION_ID)) {
@@ -401,6 +508,12 @@ RST;
 RST;
     }
 
+    /**
+     * @param string $string
+     * @param int    $indent
+     *
+     * @return string
+     */
     private function toRst($string, $indent = 0)
     {
         $string = wordwrap(Preg::replace('/(?<!`)(`.*?`)(?!`)/', '`$1`', $string), 80 - $indent);
@@ -412,6 +525,12 @@ RST;
         return $string;
     }
 
+    /**
+     * @param string $string
+     * @param int    $indent
+     *
+     * @return string
+     */
     private function indent($string, $indent)
     {
         return Preg::replace('/(\n)(?!\n|$)/', '$1'.str_repeat(' ', $indent), $string);

+ 1 - 0
src/FixerFactory.php

@@ -16,6 +16,7 @@ use PhpCsFixer\ConfigurationException\InvalidFixerConfigurationException;
 use PhpCsFixer\Fixer\ConfigurableFixerInterface;
 use PhpCsFixer\Fixer\FixerInterface;
 use PhpCsFixer\Fixer\WhitespacesAwareFixerInterface;
+use PhpCsFixer\RuleSet\RuleSetInterface;
 use Symfony\Component\Finder\Finder as SymfonyFinder;
 use Symfony\Component\Finder\SplFileInfo;
 

+ 3 - 520
src/RuleSet.php

@@ -12,9 +12,6 @@
 
 namespace PhpCsFixer;
 
-use PhpCsFixer\Fixer\FunctionNotation\NativeFunctionInvocationFixer;
-use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
-
 /**
  * Set of rules to be used by fixer.
  *
@@ -22,523 +19,9 @@ use PhpCsFixer\Fixer\PhpUnit\PhpUnitTargetVersion;
  * @author SpacePossum
  *
  * @internal
+ *
+ * @deprecated will be removed in 3.0, use \PhpCsFixer\RuleSet\RuleSet
  */
-final class RuleSet implements RuleSetInterface
+final class RuleSet extends RuleSet\RuleSet
 {
-    private $setDefinitions = [
-        '@PSR1' => [
-            'encoding' => true,
-            'full_opening_tag' => true,
-        ],
-        '@PSR2' => [
-            '@PSR1' => true,
-            'blank_line_after_namespace' => true,
-            'braces' => true,
-            'class_definition' => true,
-            'elseif' => true,
-            'function_declaration' => true,
-            'indentation_type' => true,
-            'line_ending' => true,
-            'lowercase_constants' => true,
-            'lowercase_keywords' => true,
-            'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
-            'no_break_comment' => true,
-            'no_closing_tag' => true,
-            'no_spaces_after_function_name' => true,
-            'no_spaces_inside_parenthesis' => true,
-            'no_trailing_whitespace' => true,
-            'no_trailing_whitespace_in_comment' => true,
-            'single_blank_line_at_eof' => true,
-            'single_class_element_per_statement' => ['elements' => ['property']],
-            'single_import_per_statement' => true,
-            'single_line_after_imports' => true,
-            'switch_case_semicolon_to_colon' => true,
-            'switch_case_space' => true,
-            'visibility_required' => true,
-        ],
-        '@Symfony' => [
-            '@PSR2' => true,
-            'array_syntax' => ['syntax' => 'short'],
-            'binary_operator_spaces' => true,
-            'blank_line_after_opening_tag' => true,
-            'blank_line_before_statement' => [
-                'statements' => ['return'],
-            ],
-            'braces' => [
-                'allow_single_line_closure' => true,
-            ],
-            'cast_spaces' => true,
-            'class_attributes_separation' => ['elements' => ['method']],
-            'class_definition' => ['single_line' => true],
-            'concat_space' => true,
-            'declare_equal_normalize' => true,
-            'function_typehint_space' => true,
-            'include' => true,
-            'increment_style' => true,
-            'lowercase_cast' => true,
-            'lowercase_static_reference' => true,
-            'magic_constant_casing' => true,
-            'magic_method_casing' => true,
-            'method_argument_space' => true,
-            'native_function_casing' => true,
-            'native_function_type_declaration_casing' => true,
-            'new_with_braces' => true,
-            'no_blank_lines_after_class_opening' => true,
-            'no_blank_lines_after_phpdoc' => true,
-            'no_empty_comment' => true,
-            'no_empty_phpdoc' => true,
-            'no_empty_statement' => true,
-            'no_extra_blank_lines' => ['tokens' => [
-                'curly_brace_block',
-                'extra',
-                'parenthesis_brace_block',
-                'square_brace_block',
-                'throw',
-                'use',
-            ]],
-            'no_leading_import_slash' => true,
-            'no_leading_namespace_whitespace' => true,
-            'no_mixed_echo_print' => true,
-            'no_multiline_whitespace_around_double_arrow' => true,
-            'no_short_bool_cast' => true,
-            'no_singleline_whitespace_before_semicolons' => true,
-            'no_spaces_around_offset' => true,
-            'no_superfluous_phpdoc_tags' => ['allow_mixed' => true],
-            'no_trailing_comma_in_list_call' => true,
-            'no_trailing_comma_in_singleline_array' => true,
-            'no_unneeded_control_parentheses' => true,
-            'no_unneeded_curly_braces' => ['namespaces' => true],
-            'no_unused_imports' => true,
-            'no_whitespace_before_comma_in_array' => true,
-            'no_whitespace_in_blank_line' => true,
-            'normalize_index_brace' => true,
-            'object_operator_without_whitespace' => true,
-            'ordered_imports' => true,
-            'php_unit_fqcn_annotation' => true,
-            'phpdoc_align' => [
-                // @TODO: on 3.0 switch whole rule to `=> true`, currently we use custom config that will be default on 3.0
-                'tags' => [
-                    'method',
-                    'param',
-                    'property',
-                    'return',
-                    'throws',
-                    'type',
-                    'var',
-                ],
-            ],
-            'phpdoc_annotation_without_dot' => true,
-            'phpdoc_indent' => true,
-            'phpdoc_inline_tag' => true,
-            'phpdoc_no_access' => true,
-            'phpdoc_no_alias_tag' => true,
-            'phpdoc_no_package' => true,
-            'phpdoc_no_useless_inheritdoc' => true,
-            'phpdoc_return_self_reference' => true,
-            'phpdoc_scalar' => true,
-            'phpdoc_separation' => true,
-            'phpdoc_single_line_var_spacing' => true,
-            'phpdoc_summary' => true,
-            'phpdoc_to_comment' => true,
-            'phpdoc_trim' => true,
-            'phpdoc_trim_consecutive_blank_line_separation' => true,
-            'phpdoc_types' => true,
-            'phpdoc_types_order' => [
-                'null_adjustment' => 'always_last',
-                'sort_algorithm' => 'none',
-            ],
-            'phpdoc_var_without_name' => true,
-            'return_type_declaration' => true,
-            'semicolon_after_instruction' => true,
-            'short_scalar_cast' => true,
-            'single_blank_line_before_namespace' => true,
-            'single_class_element_per_statement' => true,
-            'single_line_comment_style' => [
-                'comment_types' => ['hash'],
-            ],
-            'single_quote' => true,
-            'single_trait_insert_per_statement' => true,
-            'space_after_semicolon' => [
-                'remove_in_empty_for_expressions' => true,
-            ],
-            'standardize_increment' => true,
-            'standardize_not_equals' => true,
-            'ternary_operator_spaces' => true,
-            'trailing_comma_in_multiline_array' => true,
-            'trim_array_spaces' => true,
-            'unary_operator_spaces' => true,
-            'whitespace_after_comma_in_array' => true,
-            'yoda_style' => true,
-        ],
-        '@Symfony:risky' => [
-            'dir_constant' => true,
-            'ereg_to_preg' => true,
-            'error_suppression' => true,
-            'fopen_flag_order' => true,
-            'fopen_flags' => ['b_mode' => false],
-            'function_to_constant' => [
-                'functions' => [
-                    'get_called_class',
-                    'get_class',
-                    'get_class_this',
-                    'php_sapi_name',
-                    'phpversion',
-                    'pi',
-                ],
-            ],
-            'implode_call' => true,
-            'is_null' => true,
-            'modernize_types_casting' => true,
-            'native_constant_invocation' => [
-                'fix_built_in' => false,
-                'include' => [
-                    'DIRECTORY_SEPARATOR',
-                    'PHP_SAPI',
-                    'PHP_VERSION_ID',
-                ],
-                'scope' => 'namespaced',
-            ],
-            'native_function_invocation' => [
-                'include' => [NativeFunctionInvocationFixer::SET_COMPILER_OPTIMIZED],
-                'scope' => 'namespaced',
-                'strict' => true,
-            ],
-            'no_alias_functions' => true,
-            'no_homoglyph_names' => true,
-            'no_unneeded_final_method' => true,
-            'non_printable_character' => true,
-            'php_unit_construct' => true,
-            'php_unit_mock_short_will_return' => true,
-            'psr4' => true,
-            'self_accessor' => true,
-            'set_type_to_cast' => true,
-        ],
-        '@PhpCsFixer' => [
-            '@Symfony' => true,
-            'align_multiline_comment' => true,
-            'array_indentation' => true,
-            'blank_line_before_statement' => true,
-            'combine_consecutive_issets' => true,
-            'combine_consecutive_unsets' => true,
-            'compact_nullable_typehint' => true,
-            'escape_implicit_backslashes' => true,
-            'explicit_indirect_variable' => true,
-            'explicit_string_variable' => true,
-            'fully_qualified_strict_types' => true,
-            'heredoc_to_nowdoc' => true,
-            'method_argument_space' => ['on_multiline' => 'ensure_fully_multiline'],
-            'method_chaining_indentation' => true,
-            'multiline_comment_opening_closing' => true,
-            'multiline_whitespace_before_semicolons' => ['strategy' => 'new_line_for_chained_calls'],
-            'no_alternative_syntax' => true,
-            'no_binary_string' => true,
-            'no_extra_blank_lines' => ['tokens' => [
-                'break',
-                'continue',
-                'curly_brace_block',
-                'extra',
-                'parenthesis_brace_block',
-                'return',
-                'square_brace_block',
-                'throw',
-                'use',
-            ]],
-            'no_null_property_initialization' => true,
-            'no_short_echo_tag' => true,
-            'no_superfluous_elseif' => true,
-            'no_unset_cast' => true,
-            'no_useless_else' => true,
-            'no_useless_return' => true,
-            'ordered_class_elements' => true,
-            'php_unit_internal_class' => true,
-            'php_unit_method_casing' => true,
-            'php_unit_ordered_covers' => true,
-            'php_unit_test_class_requires_covers' => true,
-            'phpdoc_add_missing_param_annotation' => true,
-            'phpdoc_no_empty_return' => true,
-            'phpdoc_order' => true,
-            'phpdoc_types_order' => true,
-            'phpdoc_var_annotation_correct_order' => true,
-            'protected_to_private' => true,
-            'return_assignment' => true,
-            'simple_to_complex_string_variable' => true,
-            'single_line_comment_style' => true,
-        ],
-        '@PhpCsFixer:risky' => [
-            '@Symfony:risky' => true,
-            'comment_to_phpdoc' => true,
-            'final_internal_class' => true,
-            'logical_operators' => true,
-            'no_alias_functions' => ['sets' => ['@all']],
-            'no_unreachable_default_argument_value' => true,
-            'no_unset_on_property' => true,
-            'php_unit_set_up_tear_down_visibility' => true,
-            'php_unit_strict' => true,
-            'php_unit_test_annotation' => true,
-            'php_unit_test_case_static_method_calls' => true,
-            'strict_comparison' => true,
-            'strict_param' => true,
-            'string_line_ending' => true,
-        ],
-        '@DoctrineAnnotation' => [
-            'doctrine_annotation_array_assignment' => [
-                'operator' => ':',
-            ],
-            'doctrine_annotation_braces' => true,
-            'doctrine_annotation_indentation' => true,
-            'doctrine_annotation_spaces' => [
-                'before_array_assignments_colon' => false,
-            ],
-        ],
-        '@PHP56Migration' => [],
-        '@PHP56Migration:risky' => [
-            'pow_to_exponentiation' => true,
-        ],
-        '@PHP70Migration' => [
-            '@PHP56Migration' => true,
-            'ternary_to_null_coalescing' => true,
-        ],
-        '@PHP70Migration:risky' => [
-            '@PHP56Migration:risky' => true,
-            'combine_nested_dirname' => true,
-            'declare_strict_types' => true,
-            'non_printable_character' => [
-                'use_escape_sequences_in_strings' => true,
-            ],
-            'random_api_migration' => ['replacements' => [
-                'mt_rand' => 'random_int',
-                'rand' => 'random_int',
-            ]],
-        ],
-        '@PHP71Migration' => [
-            '@PHP70Migration' => true,
-            'visibility_required' => ['elements' => [
-                'const',
-                'method',
-                'property',
-            ]],
-        ],
-        '@PHP71Migration:risky' => [
-            '@PHP70Migration:risky' => true,
-            'void_return' => true,
-        ],
-        '@PHP73Migration' => [
-            '@PHP71Migration' => true,
-            'heredoc_indentation' => true,
-        ],
-        '@PHP80Migration' => [
-            '@PHP73Migration' => true,
-            'no_unset_cast' => true,
-            'normalize_index_brace' => true,
-        ],
-        '@PHP80Migration:risky' => [
-            '@PHP71Migration:risky' => true,
-            'implode_call' => true,
-            'no_alias_functions' => ['sets' => ['@all']],
-            'no_unneeded_final_method' => true,
-        ],
-        '@PHPUnit30Migration:risky' => [
-            'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_3_0],
-        ],
-        '@PHPUnit32Migration:risky' => [
-            '@PHPUnit30Migration:risky' => true,
-            'php_unit_no_expectation_annotation' => ['target' => PhpUnitTargetVersion::VERSION_3_2],
-        ],
-        '@PHPUnit35Migration:risky' => [
-            '@PHPUnit32Migration:risky' => true,
-            'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_3_5],
-        ],
-        '@PHPUnit43Migration:risky' => [
-            '@PHPUnit35Migration:risky' => true,
-            'php_unit_no_expectation_annotation' => ['target' => PhpUnitTargetVersion::VERSION_4_3],
-        ],
-        '@PHPUnit48Migration:risky' => [
-            '@PHPUnit43Migration:risky' => true,
-            'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_4_8],
-        ],
-        '@PHPUnit50Migration:risky' => [
-            '@PHPUnit48Migration:risky' => true,
-            'php_unit_dedicate_assert' => true,
-        ],
-        '@PHPUnit52Migration:risky' => [
-            '@PHPUnit50Migration:risky' => true,
-            'php_unit_expectation' => ['target' => PhpUnitTargetVersion::VERSION_5_2],
-        ],
-        '@PHPUnit54Migration:risky' => [
-            '@PHPUnit52Migration:risky' => true,
-            'php_unit_mock' => ['target' => PhpUnitTargetVersion::VERSION_5_4],
-        ],
-        '@PHPUnit55Migration:risky' => [
-            '@PHPUnit54Migration:risky' => true,
-            'php_unit_mock' => ['target' => PhpUnitTargetVersion::VERSION_5_5],
-        ],
-        '@PHPUnit56Migration:risky' => [
-            '@PHPUnit55Migration:risky' => true,
-            'php_unit_dedicate_assert' => ['target' => PhpUnitTargetVersion::VERSION_5_6],
-            'php_unit_expectation' => ['target' => PhpUnitTargetVersion::VERSION_5_6],
-        ],
-        '@PHPUnit57Migration:risky' => [
-            '@PHPUnit56Migration:risky' => true,
-            'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_5_7],
-        ],
-        '@PHPUnit60Migration:risky' => [
-            '@PHPUnit57Migration:risky' => true,
-            'php_unit_namespaced' => ['target' => PhpUnitTargetVersion::VERSION_6_0],
-        ],
-        '@PHPUnit75Migration:risky' => [
-            '@PHPUnit60Migration:risky' => true,
-            'php_unit_dedicate_assert_internal_type' => ['target' => PhpUnitTargetVersion::VERSION_7_5],
-        ],
-    ];
-
-    /**
-     * Set that was used to generate group of rules.
-     *
-     * The key is name of rule or set, value is bool if the rule/set should be used.
-     *
-     * @var array
-     */
-    private $set;
-
-    /**
-     * Group of rules generated from input set.
-     *
-     * The key is name of rule, value is bool if the rule/set should be used.
-     * The key must not point to any set.
-     *
-     * @var array
-     */
-    private $rules;
-
-    public function __construct(array $set = [])
-    {
-        foreach ($set as $key => $value) {
-            if (\is_int($key)) {
-                throw new \InvalidArgumentException(sprintf('Missing value for "%s" rule/set.', $value));
-            }
-        }
-
-        $this->set = $set;
-        $this->resolveSet();
-    }
-
-    public static function create(array $set = [])
-    {
-        return new self($set);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function hasRule($rule)
-    {
-        return \array_key_exists($rule, $this->rules);
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getRuleConfiguration($rule)
-    {
-        if (!$this->hasRule($rule)) {
-            throw new \InvalidArgumentException(sprintf('Rule "%s" is not in the set.', $rule));
-        }
-
-        if (true === $this->rules[$rule]) {
-            return null;
-        }
-
-        return $this->rules[$rule];
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getRules()
-    {
-        return $this->rules;
-    }
-
-    /**
-     * {@inheritdoc}
-     */
-    public function getSetDefinitionNames()
-    {
-        return array_keys($this->setDefinitions);
-    }
-
-    /**
-     * @param string $name name of set
-     *
-     * @return array
-     */
-    private function getSetDefinition($name)
-    {
-        if (!isset($this->setDefinitions[$name])) {
-            throw new \InvalidArgumentException(sprintf('Set "%s" does not exist.', $name));
-        }
-
-        return $this->setDefinitions[$name];
-    }
-
-    /**
-     * Resolve input set into group of rules.
-     *
-     * @return $this
-     */
-    private function resolveSet()
-    {
-        $rules = $this->set;
-        $resolvedRules = [];
-
-        // expand sets
-        foreach ($rules as $name => $value) {
-            if ('@' === $name[0]) {
-                if (!\is_bool($value)) {
-                    throw new \UnexpectedValueException(sprintf('Nested rule set "%s" configuration must be a boolean.', $name));
-                }
-
-                $set = $this->resolveSubset($name, $value);
-                $resolvedRules = array_merge($resolvedRules, $set);
-            } else {
-                $resolvedRules[$name] = $value;
-            }
-        }
-
-        // filter out all resolvedRules that are off
-        $resolvedRules = array_filter($resolvedRules);
-
-        $this->rules = $resolvedRules;
-
-        return $this;
-    }
-
-    /**
-     * Resolve set rules as part of another set.
-     *
-     * If set value is false then disable all fixers in set,
-     * if not then get value from set item.
-     *
-     * @param string $setName
-     * @param bool   $setValue
-     *
-     * @return array
-     */
-    private function resolveSubset($setName, $setValue)
-    {
-        $rules = $this->getSetDefinition($setName);
-        foreach ($rules as $name => $value) {
-            if ('@' === $name[0]) {
-                $set = $this->resolveSubset($name, $setValue);
-                unset($rules[$name]);
-                $rules = array_merge($rules, $set);
-            } elseif (!$setValue) {
-                $rules[$name] = false;
-            } else {
-                $rules[$name] = $value;
-            }
-        }
-
-        return $rules;
-    }
 }

+ 35 - 0
src/RuleSet/AbstractRuleSetDescription.php

@@ -0,0 +1,35 @@
+<?php
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\RuleSet;
+
+/**
+ * @internal
+ */
+abstract class AbstractRuleSetDescription implements RuleSetDescriptionInterface
+{
+    public function __construct()
+    {
+    }
+
+    public function getName()
+    {
+        $name = substr(static::class, 1 + strrpos(static::class, '\\'), -3);
+
+        return '@'.str_replace('Risky', ':risky', $name);
+    }
+
+    public function isRisky()
+    {
+        return false !== strpos(static::class, 'Risky');
+    }
+}

+ 161 - 0
src/RuleSet/RuleSet.php

@@ -0,0 +1,161 @@
+<?php
+
+/*
+ * This file is part of PHP CS Fixer.
+ *
+ * (c) Fabien Potencier <fabien@symfony.com>
+ *     Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ *
+ * This source file is subject to the MIT license that is bundled
+ * with this source code in the file LICENSE.
+ */
+
+namespace PhpCsFixer\RuleSet;
+
+/**
+ * Set of rules to be used by fixer.
+ *
+ * @author Dariusz Rumiński <dariusz.ruminski@gmail.com>
+ * @author SpacePossum
+ *
+ * @internal
+ * @final
+ *
+ * TODO on 3.0 make final after PhpCsFixer\RuleSet has been removed
+ */
+class RuleSet implements RuleSetInterface
+{
+    /**
+     * Group of rules generated from input set.
+     *
+     * The key is name of rule, value is bool if the rule/set should be used.
+     * The key must not point to any set.
+     *
+     * @var array
+     */
+    private $rules;
+
+    public function __construct(array $set = [])
+    {
+        foreach ($set as $key => $value) {
+            if (\is_int($key)) {
+                throw new \InvalidArgumentException(sprintf('Missing value for "%s" rule/set.', $value));
+            }
+        }
+
+        $this->resolveSet($set);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function hasRule($rule)
+    {
+        return \array_key_exists($rule, $this->rules);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRuleConfiguration($rule)
+    {
+        if (!$this->hasRule($rule)) {
+            throw new \InvalidArgumentException(sprintf('Rule "%s" is not in the set.', $rule));
+        }
+
+        if (true === $this->rules[$rule]) {
+            return null;
+        }
+
+        return $this->rules[$rule];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getRules()
+    {
+        return $this->rules;
+    }
+
+    /**
+     * @deprecated will be removed in 3.0 Use the constructor.
+     */
+    public static function create(array $set = [])
+    {
+        @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0, use the constructor.', E_USER_DEPRECATED);
+
+        return new self($set);
+    }
+
+    /**
+     * @deprecated will be removed in 3.0 Use PhpCsFixer\RuleSet\RuleSets::getSetDefinitionNames
+     */
+    public function getSetDefinitionNames()
+    {
+        @trigger_error(__METHOD__.' is deprecated and will be removed in 3.0, use PhpCsFixer\RuleSet\RuleSets::getSetDefinitionNames.', E_USER_DEPRECATED);
+
+        return RuleSets::getSetDefinitionNames();
+    }
+
+    /**
+     * Resolve input set into group of rules.
+     *
+     * @return $this
+     */
+    private function resolveSet(array $rules)
+    {
+        $resolvedRules = [];
+
+        // expand sets
+        foreach ($rules as $name => $value) {
+            if ('@' === $name[0]) {
+                if (!\is_bool($value)) {
+                    throw new \UnexpectedValueException(sprintf('Nested rule set "%s" configuration must be a boolean.', $name));
+                }
+
+                $set = $this->resolveSubset($name, $value);
+                $resolvedRules = array_merge($resolvedRules, $set);
+            } else {
+                $resolvedRules[$name] = $value;
+            }
+        }
+
+        // filter out all resolvedRules that are off
+        $resolvedRules = array_filter($resolvedRules);
+
+        $this->rules = $resolvedRules;
+
+        return $this;
+    }
+
+    /**
+     * Resolve set rules as part of another set.
+     *
+     * If set value is false then disable all fixers in set,
+     * if not then get value from set item.
+     *
+     * @param string $setName
+     * @param bool   $setValue
+     *
+     * @return array
+     */
+    private function resolveSubset($setName, $setValue)
+    {
+        $rules = RuleSets::getSetDefinition($setName)->getRules();
+
+        foreach ($rules as $name => $value) {
+            if ('@' === $name[0]) {
+                $set = $this->resolveSubset($name, $setValue);
+                unset($rules[$name]);
+                $rules = array_merge($rules, $set);
+            } elseif (!$setValue) {
+                $rules[$name] = false;
+            } else {
+                $rules[$name] = $value;
+            }
+        }
+
+        return $rules;
+    }
+}

Some files were not shown because too many files changed in this diff