Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Static Code Analysis

Static Code Analysis

Avatar for Lukáš Unger

Lukáš Unger

June 23, 2017

Other Decks in Programming

Transcript

  1. Properties of a good code • Syntactically correct ◦ Linter

    ◦ IDE • Looks nice ◦ Coding standard
  2. Properties of a good code • Syntactically correct ◦ Linter

    ◦ IDE • Looks nice ◦ Coding standard ◦ Best practices
  3. Properties of a good code • Syntactically correct ◦ Linter

    ◦ IDE • Looks nice ◦ Coding standard ◦ Best practices • Covered by tests
  4. Properties of a good code • Syntactically correct ◦ Linter

    ◦ IDE • Looks nice ◦ Coding standard ◦ Best practices • Covered by tests ◦ Unit
  5. Properties of a good code • Syntactically correct ◦ Linter

    ◦ IDE • Looks nice ◦ Coding standard ◦ Best practices • Covered by tests ◦ Unit ◦ Integration
  6. Properties of a good code • Syntactically correct ◦ Linter

    ◦ IDE • Looks nice ◦ Coding standard ◦ Best practices • Covered by tests ◦ Unit ◦ Integration ◦ Acceptance
  7. Writing tests is difficult • Cannot be automated • Prolongs

    feature delivery • Causes frustration when tests fail
  8. Writing tests is difficult • Cannot be automated • Prolongs

    feature delivery • Causes frustration when tests fail • Bikeshedding
  9. Bugs can be categorized into two classes • Bugs in

    the business logic ◦ Tests should focus on this group
  10. Bugs can be categorized into two classes • Bugs in

    the business logic ◦ Tests should focus on this group class ShoppingCart { public function add(Item $item) { $this->items = new Item(); } }
  11. Bugs can be categorized into two classes • Bugs in

    the business logic ◦ Tests should focus on this group • Bugs in code
  12. Bugs can be categorized into two classes • Bugs in

    the business logic ◦ Tests should focus on this group • Bugs in code ◦ Can be caught by Static code analysis
  13. Bugs can be categorized into two classes • Bugs in

    the business logic ◦ Tests should focus on this group • Bugs in code ◦ Can be caught by Static code analysis class Foo { } $shoppingCart->add(new Foo());
  14. Static code analysis • Analysing code without executing it. ◦

    Code is parsed into an AST and analysed directly.
  15. Static code analysis • Analysing code without executing it. ◦

    Code is parsed into an AST and analysed directly. • Allows us to reason about all possible executions of a program.
  16. Static code analysis • Analysing code without executing it. ◦

    Code is parsed into an AST and analysed directly. • Allows us to reason about all possible executions of a program. ◦ Gives assurance that the code is correct.
  17. Static code analysis • Analysing code without executing it. ◦

    Code is parsed into an AST and analysed directly. • Allows us to reason about all possible executions of a program. ◦ Gives assurance that the code is correct. • Performed by compiler in static languages.
  18. Static code analysis • Analysing code without executing it. ◦

    Code is parsed into an AST and analysed directly. • Allows us to reason about all possible executions of a program. ◦ Gives assurance that the code is correct. • Performed by compiler in static languages. ◦ Dynamic languages are not that easy to analyse.
  19. PHPStan • https://github.com/phpstan/phpstan • Ond ř ej Mirtes from Slevomat

    • 1800+ stars in ~6 months • Fast, extensible, configurable
  20. What does it do? • Existence of classes and interfaces

    in instanceof, catch, type hints, other language constructs and even annotations.
  21. What does it do? • Existence of classes and interfaces

    in instanceof, catch, type hints, other language constructs and even annotations. • Existence of variables while respecting scopes of branches and loops.
  22. What does it do? • Existence of classes and interfaces

    in instanceof, catch, type hints, other language constructs and even annotations. • Existence of variables while respecting scopes of branches and loops. • Existence and visibility of called methods and functions.
  23. What does it do? • Existence of classes and interfaces

    in instanceof, catch, type hints, other language constructs and even annotations. • Existence of variables while respecting scopes of branches and loops. • Existence and visibility of called methods and functions. • Existence and visibility of accessed properties and constants.
  24. What does it do? • Existence of classes and interfaces

    in instanceof, catch, type hints, other language constructs and even annotations. • Existence of variables while respecting scopes of branches and loops. • Existence and visibility of called methods and functions. • Existence and visibility of accessed properties and constants. • Correct types assigned to properties.
  25. What does it do? • Existence of classes and interfaces

    in instanceof, catch, type hints, other language constructs and even annotations. • Existence of variables while respecting scopes of branches and loops. • Existence and visibility of called methods and functions. • Existence and visibility of accessed properties and constants. • Correct types assigned to properties. • Correct number and types of parameters passed to constructors, methods and functions.
  26. What does it do? • Existence of classes and interfaces

    in instanceof, catch, type hints, other language constructs and even annotations. • Existence of variables while respecting scopes of branches and loops. • Existence and visibility of called methods and functions. • Existence and visibility of accessed properties and constants. • Correct types assigned to properties. • Correct number and types of parameters passed to constructors, methods and functions. • Correct types returned from methods and functions.
  27. What does it do? • Correct number of parameters passed

    to sprintf/printf calls based on format strings.
  28. What does it do? • Correct number of parameters passed

    to sprintf/printf calls based on format strings. • Useless casts like (string) 'foo'.
  29. What does it do? • Correct number of parameters passed

    to sprintf/printf calls based on format strings. • Useless casts like (string) 'foo'. • Unused constructor parameters.
  30. What does it do? • Correct number of parameters passed

    to sprintf/printf calls based on format strings. • Useless casts like (string) 'foo'. • Unused constructor parameters. • That only objects are passed to the clone keyword.
  31. What does it do? • Correct number of parameters passed

    to sprintf/printf calls based on format strings. • Useless casts like (string) 'foo'. • Unused constructor parameters. • That only objects are passed to the clone keyword. • And much more...
  32. How to use it • composer require --dev phpstan/phpstan •

    composer require --dev phpstan/phpstan-shim
  33. How to use it • composer require --dev phpstan/phpstan •

    composer require --dev phpstan/phpstan-shim ◦ PHAR
  34. How to use it • composer require --dev phpstan/phpstan •

    composer require --dev phpstan/phpstan-shim ◦ PHAR • git clone [email protected]:fprochazka/phpstan-compiler.git
  35. How to use it • composer require --dev phpstan/phpstan •

    composer require --dev phpstan/phpstan-shim ◦ PHAR • git clone [email protected]:fprochazka/phpstan-compiler.git ◦ PHAR
  36. How to use it • composer require --dev phpstan/phpstan •

    composer require --dev phpstan/phpstan-shim ◦ PHAR • git clone [email protected]:fprochazka/phpstan-compiler.git ◦ PHAR • docker pull phpstan/phpstan
  37. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants
  38. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes
  39. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes ◦ Check correct number of parameters passed to methods and functions
  40. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes ◦ Check correct number of parameters passed to methods and functions ◦ Check that constructors call parent::__construct()
  41. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes ◦ Check correct number of parameters passed to methods and functions ◦ Check that constructors call parent::__construct() ◦ Check unused constructor parameters
  42. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes ◦ Check correct number of parameters passed to methods and functions ◦ Check that constructors call parent::__construct() ◦ Check unused constructor parameters ◦ Check existence of functions and methods
  43. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes ◦ Check correct number of parameters passed to methods and functions ◦ Check that constructors call parent::__construct() ◦ Check unused constructor parameters ◦ Check existence of functions and methods ◦ Check correct number of parameters passed to sprintf/printf functions
  44. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes ◦ Check correct number of parameters passed to methods and functions ◦ Check that constructors call parent::__construct() ◦ Check unused constructor parameters ◦ Check existence of functions and methods ◦ Check correct number of parameters passed to sprintf/printf functions ◦ Check unused closure uses
  45. Levels of strictness • vendor/bin/phpstan analyse -l 0 src ◦

    Check access to properties ◦ Check access to class constants ◦ Check existence of classes ◦ Check correct number of parameters passed to methods and functions ◦ Check that constructors call parent::__construct() ◦ Check unused constructor parameters ◦ Check existence of functions and methods ◦ Check correct number of parameters passed to sprintf/printf functions ◦ Check unused closure uses ◦ Check using $this outside a class or in a static method
  46. Levels of strictness • vendor/bin/phpstan analyse -l 1 src ◦

    Check for undefined variables ◦ Check for undefined constants
  47. Levels of strictness • vendor/bin/phpstan analyse -l 3 src ◦

    Check types of items in typed arrays ◦ Check types assigned to properties (including defaults)
  48. Levels of strictness • vendor/bin/phpstan analyse -l 3 src ◦

    Check types of items in typed arrays ◦ Check types assigned to properties (including defaults) ◦ Check return types from methods and functions (including anonymous ones)
  49. Levels of strictness • vendor/bin/phpstan analyse -l 3 src ◦

    Check types of items in typed arrays ◦ Check types assigned to properties (including defaults) ◦ Check return types from methods and functions (including anonymous ones) ◦ Check that only objects are passed into the clone keyword
  50. Levels of strictness • vendor/bin/phpstan analyse -l 4 src ◦

    Check useless casts ◦ Check whether comparison always evaluates to the same boolean value
  51. Levels of strictness • vendor/bin/phpstan analyse -l 5 src ◦

    Check passed function/methods argument types (only argument count is checked on lower levels)
  52. Levels of strictness • vendor/bin/phpstan analyse -l 5 src ◦

    Check passed function/methods argument types (only argument count is checked on lower levels) ◦ Check whether an argument for parameter passed by reference is a variable
  53. Levels of strictness • vendor/bin/phpstan analyse -l 5 src ◦

    Check passed function/methods argument types (only argument count is checked on lower levels) ◦ Check whether an argument for parameter passed by reference is a variable ◦ Check whether an argument passed to count() is an array or Countable
  54. Levels of strictness • vendor/bin/phpstan analyse -l 6 src ◦

    Check compliance with union types (/** @var Foo|Bar $foobar */)
  55. Levels of strictness • vendor/bin/phpstan analyse -l 7 src ◦

    Check nullables more strictly ◦ Check whether method is called on possible nullable
  56. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions
  57. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates
  58. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates ◦ Add non-obviously assigned variables to scope
  59. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates ◦ Add non-obviously assigned variables to scope ◦ Custom early terminating method calls
  60. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates ◦ Add non-obviously assigned variables to scope ◦ Custom early terminating method calls ◦ Ignoring error messages with regular expressions
  61. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates ◦ Add non-obviously assigned variables to scope ◦ Custom early terminating method calls ◦ Ignoring error messages with regular expressions ◦ Bootstrap file
  62. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates ◦ Add non-obviously assigned variables to scope ◦ Custom early terminating method calls ◦ Ignoring error messages with regular expressions ◦ Bootstrap file ◦ Custom rules
  63. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates ◦ Add non-obviously assigned variables to scope ◦ Custom early terminating method calls ◦ Ignoring error messages with regular expressions ◦ Bootstrap file ◦ Custom rules ◦ Custom error formatters
  64. Configuration • vendor/bin/phpstan analyse -c phpstan.neon src ◦ Autoloading ◦

    Exclude files from analysis ◦ Custom file extensions ◦ Universal object crates ◦ Add non-obviously assigned variables to scope ◦ Custom early terminating method calls ◦ Ignoring error messages with regular expressions ◦ Bootstrap file ◦ Custom rules ◦ Custom error formatters ◦ Custom extensions
  65. Extending • “Magical” class properties class Foo { private $data

    = []; public function __get($name) { return $this->data($name) ?? null; } public function __set($name, $value) { $this->data[$name] = $value; } } (new Foo())->bar = 1;
  66. Extending • “Magical” class properties • “Magical” class methods class

    Foo { public function __call($name, $arguments) { return call_user_func_array($name, $arguments); } } (new Foo())->strlen(‘foobar’);
  67. Extending • “Magical” class properties • “Magical” class methods •

    Dynamic method return types $service = $container->getByType(Foo::class);
  68. Real life example • 3MW • PHPStan 0.7 with Nette

    and Doctrine extensions • 2499 analysed files
  69. Real life example • 3MW • PHPStan 0.7 with Nette

    and Doctrine extensions • 2499 analysed files • Level 0
  70. Real life example • 3MW • PHPStan 0.7 with Nette

    and Doctrine extensions • 2499 analysed files • Level 0 • First run 1m40s, 1.1 GB memory
  71. Real life example • 3MW • PHPStan 0.7 with Nette

    and Doctrine extensions • 2499 analysed files • Level 0 • First run 1m40s, 1.1 GB memory ◦ Second run 49s, 762 MB memory
  72. Real life example • 3MW • PHPStan 0.7 with Nette

    and Doctrine extensions • 2499 analysed files • Level 0 • First run 1m40s, 1.1 GB memory ◦ Second run 49s, 762 MB memory • 373 errors
  73. Real life example • 3MW • PHPStan 0.7 with Nette

    and Doctrine extensions • 2499 analysed files • Level 0 • First run 1m40s, 1.1 GB memory ◦ Second run 49s, 762 MB memory • 373 errors • Level 7 - 4504 errors
  74. Real life example • 3MW • PHPStan 0.7 with Nette

    and Doctrine extensions • 2499 analysed files • Level 0 • First run 1m40s, 1.1 GB memory ◦ Second run 49s, 762 MB memory • 373 errors • Level 7 - 4504 errors ◦ Probably many false positives