First Commit

This commit is contained in:
mark committed 2026-10-19 15:22:52 -07:00
1 parent 5eb9dd037d
commit 2e62c0e60b
11877 files changed
+2035312

No files matched your search

+828
View File
@@ -0,0 +1,828 @@
pdepend-2.16.2 (2023/12/17)
==========================
- Fixed [#705](https://github.com/pdepend/pdepend/pull/705): Fix throw-expression parsing inside array access
pdepend-2.16.1 (2023/12/10)
==========================
- Fixed [#699](https://github.com/pdepend/pdepend/pull/699): Fix Symfony 7 compatibility
pdepend-2.16.0 (2023/11/29)
==========================
- Added [#692](https://github.com/pdepend/pdepend/pull/692) PHP 8.3 Syntax
- Added [#686](https://github.com/pdepend/pdepend/pull/686) Allow Symfony 7
- Fixed [#691](https://github.com/pdepend/pdepend/pull/691) Float parsing for number starting with 0.
- Fixed [#689](https://github.com/pdepend/pdepend/pull/689) Handle conversion to/detection of UTF-8 encoding using either mbstring PHP extension or the polyfill provided by Symfony
- Fixed [phpmd/phpmd#914](https://github.com/pdepend/pdepend/pull/687) Parsing the correct comment for method doc-block (Allow correct SuppressWarnings annotation handling on PHPMD)
- Fixed [phpmd/phpmd#804](https://github.com/pdepend/pdepend/pull/694) Handle yield termination depending on context
pdepend-2.15.1 (2023/09/28)
==========================
- Fixed [\#684](https://github.com/pdepend/pdepend/pull/684): Fix [\#682](https://github.com/pdepend/pdepend/issues/682) Re-allow empty compilation unit
- Changed [\#684](https://github.com/pdepend/pdepend/pull/684): Show error full stack trace when debug is on
pdepend-2.15.0 (2023/09/23)
==========================
- Fixed [\#669](https://github.com/pdepend/pdepend/pull/669): Fix Halstead formula.
- Fixed [\#673](https://github.com/pdepend/pdepend/pull/673): Fix [\#665](https://github.com/pdepend/pdepend/issues/665) Allow readonly before public/protected/private.
- Changed [\#670](https://github.com/pdepend/pdepend/pull/670): Upgrade the GitHub Actions from V2 to V3.
- Changed [\#671](https://github.com/pdepend/pdepend/pull/671): Update PHPStan to 1.10.25.
- Changed [\#672](https://github.com/pdepend/pdepend/pull/672) and [\#676](https://github.com/pdepend/pdepend/pull/676): Resolve edge cases cought by PHPStan level 7.
- Changed [\#675](https://github.com/pdepend/pdepend/pull/675): Run the codecoverage with PHP 8.2 and use xDebug 3.
- Changed [\#677](https://github.com/pdepend/pdepend/pull/677) and [\#678](https://github.com/pdepend/pdepend/pull/678): Add more tests.
pdepend-2.14.0 (2023/05/26)
==========================
- Added [\#663](https://github.com/pdepend/pdepend/pull/663): Added, sign the phar files.
- Added [\#657](https://github.com/pdepend/pdepend/pull/657): Added keywords to composer.json.
- Fixed [\#656](https://github.com/pdepend/pdepend/pull/656): Fix [\#635](https://github.com/pdepend/pdepend/issues/635), [\#650](https://github.com/pdepend/pdepend/issues/650) Base enum label validity on constant name rule.
- Fixed [\#661](https://github.com/pdepend/pdepend/pull/661): Fix [\#639](https://github.com/pdepend/pdepend/issues/639) Handle extra parenthis for functions.
pdepend-2.13.0 (2023/02/28)
==========================
- Added [\#636](https://github.com/pdepend/pdepend/pull/636): Add support for NULL, DEFAULT and NEW as enum case.
- Added [\#651](https://github.com/pdepend/pdepend/pull/651): Add a follow on mastodon link to the footer on the website.
- Fixed [\#633](https://github.com/pdepend/pdepend/pull/633): Fix parsing for new with parentheses.
- Fixed [\#641](https://github.com/pdepend/pdepend/pull/641): Improve UTF-8 encoding process.
- Fixed [\#637](https://github.com/pdepend/pdepend/pull/637): Prevent the use of a not set id value in the AbstractASTType and AbstractASTCallable.
- Fixed [\#642](https://github.com/pdepend/pdepend/pull/642): Fix [\#638](https://github.com/pdepend/pdepend/issue/638) Unexpected Token with double class modifiers.
- Changed [\#644](https://github.com/pdepend/pdepend/pull/644): Correct collection of Enum and Intersection type information during analysis.
- Changed [\#646](https://github.com/pdepend/pdepend/pull/646): Numeric-strings.
- Changed [\#647](https://github.com/pdepend/pdepend/pull/647): Phpstan corrections.
- Changed [\#648](https://github.com/pdepend/pdepend/pull/648): Correct type signatures.
- Changed [\#645](https://github.com/pdepend/pdepend/pull/645): Correct name space collection types (bump to PHPStan level 5).
- Changed [\#649](https://github.com/pdepend/pdepend/pull/649): Add missing type information.
- Changed [\#654](https://github.com/pdepend/pdepend/pull/654): Increase PHPStan to level 6.
pdepend-2.12.1 (2022/09/08)
==========================
- Fixed [\#631](https://github.com/pdepend/pdepend/pull/631): Fix enum visit
pdepend-2.12.0 (2022/09/07)
==========================
- Added [\#618](https://github.com/pdepend/pdepend/pull/618): Implement support for PHP 8.2 null/false stand-alone type
- Added [\#620](https://github.com/pdepend/pdepend/pull/620): Implement support for PHP 8.2 true type
- Added [\#625](https://github.com/pdepend/pdepend/pull/625): Implement support for PHP 8.2 Readonly Classes
- Added [\#626](https://github.com/pdepend/pdepend/pull/626): Implement support for PHP 8.2 Disjunctive Normal Form Types
- Fixed [\#630](https://github.com/pdepend/pdepend/pull/630): Fix parsing of by-reference vararg parameters
pdepend-2.11.1 (2022/09/01)
==========================
- Fixed [\#622](https://github.com/pdepend/pdepend/pull/622): Fix ASTEnum serialization
pdepend-2.11.0 (2022/08/29)
==========================
- Added [\#600](https://github.com/pdepend/pdepend/pull/600): Support integer non-decimal notations
- Added [\#598](https://github.com/pdepend/pdepend/pull/598): Support PHP 8.1 in-initializers
- Added [\#610](https://github.com/pdepend/pdepend/pull/610): Support PHP 8.1 support pure intersection types
- Added [\#613](https://github.com/pdepend/pdepend/pull/613): Support PHP 8.1 first class callable syntax
- Added [\#608](https://github.com/pdepend/pdepend/pull/608): Support PHP 8.1 enums
- Fixed [\#593](https://github.com/pdepend/pdepend/pull/593): Fix cache for STDIN usage
- Fixed [\#603](https://github.com/pdepend/pdepend/pull/603): Allow coma-separated variables in short-tags
- Fixed [\#604](https://github.com/pdepend/pdepend/pull/604): Support key variable in list unpacking
pdepend-2.10.3 (2022/02/23)
==========================
- Added [\#574](https://github.com/pdepend/pdepend/pull/574): Support symfony 6
- Fixed [\#583](https://github.com/pdepend/pdepend/pull/583), [\#578](https://github.com/pdepend/pdepend/pull/578), [\#577](https://github.com/pdepend/pdepend/pull/577), [\#576](https://github.com/pdepend/pdepend/pull/576) : Add declare ReturnTypeWillChange to fix deprecation warnings.
- Fixed [\#575](https://github.com/pdepend/pdepend/pull/575): Fix deprecation warning in AbstractPHPParser::parseVarAnnotation.
- Fixed [\#579](https://github.com/pdepend/pdepend/pull/579): Fix deprecation messages in AbstractPHPParser::prepareCallable
- Changed [\#589](https://github.com/pdepend/pdepend/pull/589), [\#588](https://github.com/pdepend/pdepend/pull/588), [\#587](https://github.com/pdepend/pdepend/pull/587), [\#586](https://github.com/pdepend/pdepend/pull/586), [\#585](https://github.com/pdepend/pdepend/pull/585), [\#582](https://github.com/pdepend/pdepend/pull/582), [\#581](https://github.com/pdepend/pdepend/pull/581), [\#580](https://github.com/pdepend/pdepend/pull/580) : Internal code cleanup and PHPStan fixes.
pdepend-2.10.2 (2021/11/16)
==========================
- Added [\#568](https://github.com/pdepend/pdepend/pull/568): Support PHP 8.1 final constants.
- Fixed [\#572](https://github.com/pdepend/pdepend/pull/572): Allow "readonly" as part of a class name.
- Fixed [\#567](https://github.com/pdepend/pdepend/pull/567): Allow const, field, method named readonly.
pdepend-2.10.1 (2021/10/11)
==========================
- Added [\#563](https://github.com/pdepend/pdepend/pull/563): Support PHP 8.1 `never` return type.
- Added [\#565](https://github.com/pdepend/pdepend/pull/565): Support PHP 8.1 readonly properties.
- Added [\#561](https://github.com/pdepend/pdepend/pull/561): Support trailing comma in `isset()` and `unset()` lists.
- Fixed [\#562](https://github.com/pdepend/pdepend/pull/562): Allow any keyword as the name of an argument.
- Fixed [\#555](https://github.com/pdepend/pdepend/pull/555): Restore modifier after serialization.
pdepend-2.10.0 (2021/07/20)
==========================
- Added [\#534](https://github.com/pdepend/pdepend/pull/534): Support trailing comma in parameters list.
- Added [\#535](https://github.com/pdepend/pdepend/pull/535): Support trailing comma in closure list.
- Added [\#538](https://github.com/pdepend/pdepend/pull/538): Add named argument value as child to make it discoverable.
- Added [\#540](https://github.com/pdepend/pdepend/pull/540): Support throw expression.
- Added [\#543](https://github.com/pdepend/pdepend/pull/543): Support multiple expressions as match key.
- Fixed [\#530](https://github.com/pdepend/pdepend/pull/530): Automate release generation for the website.
- Fixed [\#537](https://github.com/pdepend/pdepend/pull/537): Match expression does not have namespace
- Fixed [\#541](https://github.com/pdepend/pdepend/pull/541): Fix support for union types
- Fixed [\#544](https://github.com/pdepend/pdepend/pull/544): Math throw entry may end on curly braces
- Fixed [\#547](https://github.com/pdepend/pdepend/pull/547): Add the phar to the website. The new URL is: https://pdepend.org/static/latest/pdepend.phar
- Fixed [\#550](https://github.com/pdepend/pdepend/pull/550): Allow multiple arguments in invocation
- Fixed [\#551](https://github.com/pdepend/pdepend/pull/551): Allow null and false in union type for typed properties
- Fixed [\#552](https://github.com/pdepend/pdepend/pull/552): Allow null-safe operator anywhere object operator is allowed
pdepend-2.9.1 (2021/04/15)
==========================
- Added [\#519](https://github.com/pdepend/pdepend/issues/519): Support PHP 7.2 trailing commas in grouped use declarations
- Added [\#518](https://github.com/pdepend/pdepend/issues/518): Support PHP 8 `static` type hint
- Added [\#522](https://github.com/pdepend/pdepend/issues/522): Support PHP 8 `null` and `false` type hint
- Added [\#516](https://github.com/pdepend/pdepend/issues/516): Support PHP 8 catch without variable
- Fixed [\#527](https://github.com/pdepend/pdepend/issues/527): Allow nested arrays in PHP 8 attributes
pdepend-2.9.0 (2021/03/11)
==========================
- Added [\#496](https://github.com/pdepend/pdepend/issues/496) Support PHP 8 Match expression
- Added [\#494](https://github.com/pdepend/pdepend/issues/494) Support PHP 8 Constructor property promotion
- Added [\#492](https://github.com/pdepend/pdepend/issues/492) Support PHP 8 Named arguments
- Added [\#493](https://github.com/pdepend/pdepend/issues/493) Support PHP 8 Attributes
- Added [\#495](https://github.com/pdepend/pdepend/issues/495) Support PHP 8 Union types
- Added [\#497](https://github.com/pdepend/pdepend/issues/497) Support PHP 8 Nullsafe operator
- Added [\#491](https://github.com/pdepend/pdepend/issues/491) Support PHP 8 tokens changes
- Fixed [\#490](https://github.com/pdepend/pdepend/pull/490) Preserve short open tags
- Fixed [\#480](https://github.com/pdepend/pdepend/pull/480), [\#486](https://github.com/pdepend/pdepend/pull/486) and [\#513](https://github.com/pdepend/pdepend/pull/513) PHPDoc blocks
- Changed [\#500](https://github.com/pdepend/pdepend/issues/500) Switch to GitHub Actions
- Changed [\#511](https://github.com/pdepend/pdepend/pull/511) Run PHPStan in GitHub actions
- Changed [\#489](https://github.com/pdepend/pdepend/pull/489) Add unit tests for Application class
- Removed [\#488](https://github.com/pdepend/pdepend/pull/488) Removed changes.xml legacy file
pdepend-2.8.0 (2020/05/25)
==========================
- Added [\#458](https://github.com/pdepend/pdepend/pull/458) Support trait insteadof overrides. (Issue [\#367](https://github.com/pdepend/pdepend/issues/367) and [\#320](https://github.com/pdepend/pdepend/issues/320) )
- Added [\#466](https://github.com/pdepend/pdepend/pull/466) Allow to configure file cache ttl in configuration file. (Issue [\#465](https://github.com/pdepend/pdepend/issues/465))
- Added [\#487](https://github.com/pdepend/pdepend/pull/484) Support arrow functions return type hints.
- Fixed [\#467](https://github.com/pdepend/pdepend/pull/467) Use the HOME env variable also for Windows. (Issue [\#447](https://github.com/pdepend/pdepend/issue/447) )
- Fixed [\#475](https://github.com/pdepend/pdepend/pull/475) Fixed [\#474](https://github.com/pdepend/pdepend/issues/474) typed property visibility
- Fixed [\#476](https://github.com/pdepend/pdepend/pull/476) Fixed [\#473](https://github.com/pdepend/pdepend/issues/473) handle skipped variable in destructuring array
- Fixed [\#478](https://github.com/pdepend/pdepend/pull/478) Fixed [\#472](https://github.com/pdepend/pdepend/issues/472) Use the current token instead of the first inner one to determine the class start.
- Fixed [\#483](https://github.com/pdepend/pdepend/pull/483) Fixed bool flip in parseEscapedAstLiteralString()
- Fixed [\#479](https://github.com/pdepend/pdepend/pull/479) Fixed [\#299](https://github.com/pdepend/pdepend/issues/299) Class constant expression declaration.
- Changed: Tidelift language ( [\#460](https://github.com/pdepend/pdepend/pull/460), [\#461](https://github.com/pdepend/pdepend/pull/461) and [\#462](https://github.com/pdepend/pdepend/pull/462) )
- Changed: Interal cleanup with refactoring and adding missing PHPDoc ( [\#477](https://github.com/pdepend/pdepend/pull/477), [\#484](https://github.com/pdepend/pdepend/pull/484) and [\#485](https://github.com/pdepend/pdepend/pull/485) )
pdepend-2.7.1 (2020/02/12)
==========================
- Fixed [\#453](https://github.com/pdepend/pdepend/pull/453) Support for typed properties (nullable, array, FQN, scalar)
- Fixed [\#446](https://github.com/pdepend/pdepend/pull/446) Suppress E_NOTICE thrown by unserialize()
pdepend-2.7.0 (2020/01/24)
==========================
- Added [\#362](https://github.com/pdepend/pdepend/pull/362) Support for php:// stream wrappers
- Added [\#427](https://github.com/pdepend/pdepend/pull/427) PHP 7.4 features support
pdepend-2.6.1 (2019/12/21)
==========================
- Added [\#398](https://github.com/pdepend/pdepend/pull/398) Support for Symfony 5
- Fixed [\#299](https://github.com/pdepend/pdepend/pull/299) Array concatenation in constant declaration
pdepend-2.6.0 (2019/12/16)
==========================
- Added [\#383](https://github.com/pdepend/pdepend/pull/383) Support of PHP 7.1 syntax
- Fixed [\#386](https://github.com/pdepend/pdepend/pull/386) PHP 7 and parsing some return types
- Fixed [\#381](https://github.com/pdepend/pdepend/pull/381) Unexpected token error with invokable
- Fixed [\#365](https://github.com/pdepend/pdepend/pull/365) unable to call method on newly created and invoked class
- Removed not needed files from the export used by composer
pdepend-2.5.2 (2017/12/13)
==========================
This release contains a single bugfix for missing command options.
- Fix for GH355: Unknown option --jdepend-chart [\#356](https://github.com/pdepend/pdepend/pull/356) ([manuelpichler](https://github.com/manuelpichler))
pdepend-2.5.1 (2017/12/06)
==========================
This release contains many bugfixes, enables Scrutinizer and adds code coverage integration. HHVM support was dropped. Full support for missing language features for PHP <= 7.1 were added.
- Support for "yield from" in PHP 7.0 [\#350](https://github.com/pdepend/pdepend/pull/350) ([emirb](https://github.com/emirb))
- Support for constant visibility in interfaces in PHP 7.1 [\#349](https://github.com/pdepend/pdepend/pull/349) ([KacerCZ](https://github.com/KacerCZ))
- Support catch of multiple exception types in PHP 7.1 [\#348](https://github.com/pdepend/pdepend/pull/348) ([KacerCZ](https://github.com/KacerCZ))
- Added support for PHP 7.1 types - iterable and void [\#342](https://github.com/pdepend/pdepend/pull/342) ([KacerCZ](https://github.com/KacerCZ))
- Add Symfony 4 support [\#340](https://github.com/pdepend/pdepend/pull/340) ([surikman](https://github.com/surikman))
- Fix Scrutinizer config [\#336](https://github.com/pdepend/pdepend/pull/336) ([emirb](https://github.com/emirb))
- Fixed PHPUnit warnings [\#333](https://github.com/pdepend/pdepend/pull/333) ([KacerCZ](https://github.com/KacerCZ))
- Codecov explicit coverage file [\#332](https://github.com/pdepend/pdepend/pull/332) ([emirb](https://github.com/emirb))
- Add codecov.io integration [\#331](https://github.com/pdepend/pdepend/pull/331) ([emirb](https://github.com/emirb))
- Use uniqid\(\) in AbstractASTArtifact::getId\(\) instead of microtime\(\) [\#330](https://github.com/pdepend/pdepend/pull/330) ([KacerCZ](https://github.com/KacerCZ))
- Fix Iterator so it will not return directories [\#329](https://github.com/pdepend/pdepend/pull/329) ([KacerCZ](https://github.com/KacerCZ))
- Fix tests on Windows [\#328](https://github.com/pdepend/pdepend/pull/328) ([KacerCZ](https://github.com/KacerCZ))
- PHP 7.2 fixes [\#326](https://github.com/pdepend/pdepend/pull/326) ([emirb](https://github.com/emirb))
- Capitalize XML word [\#325](https://github.com/pdepend/pdepend/pull/325) ([bocharsky-bw](https://github.com/bocharsky-bw))
- Fix typo [\#321](https://github.com/pdepend/pdepend/pull/321) ([ravage84](https://github.com/ravage84))
- Fixes \#193 regression [\#319](https://github.com/pdepend/pdepend/pull/319) ([mdeboer](https://github.com/mdeboer))
- Remove running of PHP 5.3 build since dropped by Travis. [\#316](https://github.com/pdepend/pdepend/pull/316) ([niconoe-](https://github.com/niconoe-))
- Fix issue \#297 adding support for constant visibility into the parser for PHP 7.1 [\#314](https://github.com/pdepend/pdepend/pull/314) ([mmucklo](https://github.com/mmucklo))
- Remove references to HHVM [\#309](https://github.com/pdepend/pdepend/pull/309) ([ravage84](https://github.com/ravage84))
- fix count\(\): Parameter must be an array or an object that implements ... [\#303](https://github.com/pdepend/pdepend/pull/303) ([remicollet](https://github.com/remicollet))
- "a xml" -\> "an xml" [\#300](https://github.com/pdepend/pdepend/pull/300) ([bocharsky-bw](https://github.com/bocharsky-bw))
pdepend-2.5.0 (2017/01/19)
==========================
This release closes a parsing bug in PDepend 2.4.1, starts with the
implementation of PHP 7.1 support and adds a new attribute for the
fully-qualified-classname to the summary report.
- Fixed #282: Issue with grouped use statements when only a single
level namespace prefix was used. Fixed in commit #3e523f5.
- Implemented #294: Add support for PHP 7.1 optionals. Implemented in
commit #c5c53eb.
- Implemented #88: Fully qualified classname in summary report.
Implemented in commit #13e9cbc.
pdepend-2.4.1 (2017/01/11)
==========================
This release closes a bug within PDepend's parser when keywords are
used as method or constant names in PHP 7.0
- Fixes an issue with methods or constants with keyword identifiers
called/accessed in PHP 7. Fixed in commit #8f07ac7.
pdepend-2.4.0 (2017/01/10)
==========================
This release implements language features like Anonymous Classes,
Group use Declarations, Uniform Variable Syntax or Loosening Reserved
Word Restrictions that were introduced with PHP 7.0, so that PDepend
2.4 is now PHP 7.0 compatible.
- Fixed #281: PHP 7 - Anonymous Class - Internal parser state issues
Fixed in commit #00a61c6.
- Fixed #285: Parse the magic constant __TRAIT__ Fixed in commit
#b76e2b0.
- Fixed #210: Partial Class Namespace is Calculated Twice: in Global
and it's Own Namespace Fixed in commit #e81411f.
- Implemented #280: Refactor SymbolTable Implemented in commit
#1265259.
- Implemented #282: PHP 7 - Group use declarations Implemented in
commit #fd4aaca.
- Implemented #269: Unexpected token: :: (implicit object / method
usage) Implemented in commit #e611915.
- Implemented #204: Support for the ... operator in function calls
Implemented in commit #078e532.
- Implemented #290: Unexpected token: ARRAY (reserved keyword as a
class constant) Implemented in commit #d4bf7bb.
pdepend-2.3.2 (2016/11/23)
==========================
Bugfix release that closes a caching issue that was introduced in
2.3.1.
- Fixed #276: Uncaught Error: Call to a member function type() on null
in Fixed in commit #48d8081.
- Allow list as method name under PHP 7 Fixed in commit #4968ed4.
- Fixed #277: serialize(): "comment" is returned from __sleep multiple
times in store in FileCacheDriver.php Fixed in commit #31cf053.
pdepend-2.3.1 (2016/11/23)
==========================
- Fixed #250: Updating ASTAnonymousClass to implement ASTNode,
retaining class behavior. Fixed in commit #2111906.
pdepend-2.3.0 (2016/11/22)
==========================
This release closes multiple bugs/issue and has merged several
outstanding pull requests. Beside that it is now possible to pipe
source through STDIN into pdepend.
- Fixed #263: Fix NPath calculations for the ternary operator. Fixed
in commit #df0e9c5.
- Fixed #260: Fix typos Fixed in commit #20b36c1.
- Fixed #259: DOMDocument file handling. Fixed in commit #fa2afc6.
- Fixed #247: Fix handling of use declarations with const and function
keywords. Fixed in commit #dc9128b.
- Fixed #240: Fix some typos from the website. Fixed in commit
#332672a.
- Fixed #249: Unexpected token: callable Fixed in commit #.
- Support for PHP's ** pow expression implemented. Implemented in
commit #bce6145.
- Implemented #262: Support stdin implemented. Implemented in commit
#3ef2328.
- Implemented #231: Apply the filter on files as well. Implemented in
commit #62d1406.
pdepend-2.2.6 (2016/10/04)
==========================
Bugfix release.
- Fixed #267: Fix UnexpectedTokenException on null coalesce operator
Fixed in commit #8e80aaa.
pdepend-2.2.4 (2016/03/10)
==========================
This releases closes a bug in PDepend's parsing code for PHP 7 return
types, that caused a invalid state in the internal AST representation.
This bug was issued in PHPMD's issue tracker first by user radmen.
- Cannot create new nodes, when internal state is frozen. #328 Fixed
in commit #ffe9957.
pdepend-2.2.3 (2016/02/22)
==========================
This release includes several pending pull requests from GitHub.
Beside that this release adds support for complex expressions in
property, constant and parameter declarations, introduced with PHP
5.6.
- Fixed #226: Fixed division by zero issue. Fixed in commit #fb46614.
- Fixed #227: Fix support to files filters. Fixed in commit #4e150db.
- Fixed #230: Fix handling cygwin home folder location. Fixed in
commit #126c38a.
- Implemented #221: Add --quiet option. Implemented in commit
#9a710f7.
- Implemented #236: Switch to PSR-4 for autoloading Implemented in
commit #57b54bd.
- Implemented #238: Unexpected token errors for 5.6 "constant
expression" initializers. Implemented in commit #0087c94.
pdepend-2.2.2 (2015/10/16)
==========================
This release adds a new analyzer that can be used to visualize
namespace dependencies.
- Implemented #221: Added line numbers to summary log. Implemented in
commit #a975553.
- Implemented #222: Calculate type dependencies. Implemented in commit
#8a924f6.
pdepend-2.2.1 (2015/09/24)
==========================
With this release we made a dependency downgrade, so that we can
support more environments.
- Implemented #223: Minimum Symfony version downgraded to 2.3.
Implemented in commit #8601cc3.
pdepend-2.2.0 (2015/09/19)
==========================
This release contains beside several contributed additions and
bugfixes better support for PHP 7 language constructs.
- Fixed #119: PDepend doesn't follow any symlinks to directories.
Fixed in commit #b80ae7e.
- Fixed #143: Truncated summary when analyzing ISO-8859-1 input. Fixed
in commit #d979462.
- Fixed #193: Cache conflict when executing pdepend in parallel. Fixed
in commit #a4e20ff.
- Fixed #197: Warning: DOMNode::cloneNode(): ID <id> already defined
in phar. Fixed in commit #2221f74.
- Fixed #201: ShellCheck warnings in scripts/compare.sh Fixed in
commit #.
- Fixed #209: PHP 5.6 constant syntax not supported. Fixed in commit
#1209b0e.
- Fixed #213: PHP 7: T_CHARACTER and T_BAD_CHARACTER are no longer
defined. Fixed in commit #1f5b051.
- Fixed #214: PHP 7: Return types not supported. Fixed in commit
#249932b.
pdepend-2.1.0 (2015/05/21)
==========================
This release introduces an analyzer for the Halstead metrics and the
maintainability index, contributed by Matthias Mullie. Beside that we
have closed several issues and bugs in PDepend's source code.
- Fixed #196: Fix Typo in phpDoc Fixed in commit #2b51fed.
- Fixed #200: Fix annotation-typo in AbstractPHPParser.php Fixed in
commit #776529d.
- Fixed #202: Support for variable arg list implemented Fixed in
commit #dff2547.
- Implemented #177: HHVM support Implemented in commit #48ee5d9.
- Implemented #185: Remove unused imports and order alphabetically
Implemented in commit #46d5fb.
- Implemented #198: Add analyzers for Halstead measures &
maintainability index Implemented in commit #3497862.
pdepend-2.0.6 (2015/03/02)
==========================
Concurrency issue in the file cache garbage collector fixed.
- Suppress exceptions when there are concurrency issues within the
garbage collector. Fixed in commit #3e31cc7.
pdepend-2.0.5 (2015/02/27)
==========================
This release just adds a simple garbage collector for PDepend's file
cache
- Garbage collector for old cache files added. Implemented in commit
#56712b1.
pdepend-2.0.4 (2014/12/04)
==========================
This release closes some minor issues and incorporates several
outstanding pull requests.
- Fixed #187: Unexpected token :?> with broken up switch statement
Fixed in commit #c12ee0e.
- Fixed #180: Unexpected token: <<, line: 5, col: 27 Fixed in commit
#4df5b9d.
- Fixed #179: Fixed display of duration longer than one hour Fixed in
commit #1288292.
- Fixed #176: Typo on website fixed. Fixed in commit #6a8e542.
- Fixed #175: Inconsistent indention in phpunit.dist.xml file fixed.
Fixed in commit #bc758e4.
- Fixed #174: Fix conflicting import: "Extension" is already in use in
the "PDepend\DependencyInjection" namespace. Fixed in commit
#e3e672b.
- Fixed #173: Fixing parsing True/False keywords in namespaces: Usage
of true and false keywords are allowed in namespace declarations in
PHP. Fixed in commit #d96e4e7.
- Fixed #170: invalid xml-report after parsing traits Fixed in commit
#1d1bec0.
- Fixed #167: Fix Invalid argument supplied for foreach() in
FileCacheDriver.php Fixed in commit #73d32f3.
- Fixed #165: Fix FileUtil::getUserHomeDir on Mac Fixed in commit
#4826c3f.
- Fixed #164: Empty yields raise Fatal error: When using empty yields
yield; the parser raises an fatal error. Fixed in commit #7ab0736.
- Fixed #163: File cache concurrency fix: Fixes concurrent run of
pdepend and phpmd. Fixed in commit #3955c07.
- Fixed #154: Invalid trait conflict errors: t is completely valid to
mix traits in PHP that have the same methods declared, as long as
only one of them is concrete (all the others must be abstract).
Fixed in commit #45ab1d3.
- Fixed #128: Problem when I use parent:: in trait Fixed in commit
#a73e6de.
- Implemented #177: HHVM support Implemented in commit #17da34b.
pdepend-2.0.3 (2014/10/08)
==========================
This is a bugfix release which closes some minor issues.
- Fixed #129: Windows+Composer install fails due to "path too long"
Fixed in commit #64f95c1.
- Fixed #172: Outdated news on the website
- Fixed #166: Added support for foreach with list statement (PHP 5.5)
Fixed in commit #a744af1.
- Fixed #171: The list usage in foreach loops reports an invalid token
Fixed in commit #a744af1.
pdepend-2.0.2 (2014/09/16)
==========================
- Fixed #160: include_once PDepend/Util/Coverage/CloverReport.php:
failed to open stream Fixed in commit #4dca605.
- Implemented #105: Support Java style array notations in doc comments
Implemented in commit #2ec5166.
pdepend-2.0.1 (2014/09/09)
==========================
Bug fix release which closes a issue within PDepend's C.R.A.P. index
calculation.
- Handle code surrounded by @codeCoverageIgnore annotations correct.
Fixed in commit #3e67aa2.
pdepend-2.0.0 (2014/05/21)
==========================
New mayor release of PDepend.
- Fixed #126: Allow closure as array element Fixed in commit #b9775ac.
- Fixed #153: Support for new finally keyword implemented. Fixed in
commit #e536e7a.
- Fixed #144: pdepend --version gives me a wrong message.. Fixed in
commit #f6acea9.
- Implemented #113: Specify license, BSD license was missing in
composer.json file. Implemented in commit #3ba9c9e.
- Implemented #117: Adds composer autoload info Implemented in commit
#e624f8e.
pdepend-1.1.1 (2013/07/25)
==========================
Closes several PHP 5.4 issues.
- Fixed #116: Adding a fix for PHP 5.4 style arrays. Fixed in commit
#cbfddaa.
- Fixed #95: PHP 5.4 array syntax is not supported in property
initialization. Fixed in commit #f6ee217.
- Fixed #97: protected property PHP_Depend_Code_Method::$parent Fixed
in commit #87a1b5e.
- Fixed #104: Syntax errors reported when PHP 5.4 short array syntax
is used in method signatures or class variable definitions. Fixed in
commit #d731fa6.
- Fixed #103: Fix syntax error in composer.json example Fixed in
commit #e897a66.
- Implemented #101: Package name for chart svg Implemented in commit
#479aaa5.
pdepend-1.1.0 (2012/09/12)
==========================
This release closes a critical issue in the context of traits
handling.
- Changed type of Node/Trait Fixed in commit #806eaab.
- Changed to PSR1 coding standard. Implemented in commit #.
pdepend-1.0.7 (2012/04/29)
==========================
This release closes a minor bug within the parsing code for doc
comments..
- Fixed: DocComment is sometimes incorrectly set for functions Fixed
in commit #ac71753.
pdepend-1.0.6 (2012/04/22)
==========================
This release closes a bug with traits that were introduced with PHP
5.4. This bug results in an E_FATAL when PHP_Depend performs coupling
analysis on a trait.
- Fixed: E_FATAL when the coupling analyzer processes a trait. Fixed
in commit #ac71753.
- Added: Composer support Implemented in commit #3d98f02.
pdepend-1.0.5 (2012/04/05)
==========================
This release closes a bug introduced with the last release, which
causes PHP_Depend not to flush it's metric cache when a file has
changed.
- Fixed #27588643: PHP_Depend doesn't invalidate the cache. Fixed in
commit #99d5c13.
pdepend-1.0.4 (2012/02/25)
==========================
This release closes an issue introduced with the last release. It
closes one more regression related to PHP's memory_limit and the
Suhosin patch.
- Fixed fatal error due to bug in memory_limit modification code.
Fixed in commit #b869eff.
pdepend-1.0.3 (2012/02/25)
==========================
This release closes a minor issue in PHP_Depend's memory handling when
it is run in a PHP environment that uses the Suhosin patch and the
suhosin.memory_limit setting.
- Fixed #25450915: Alert disable memory_limit Fixed in commit
#0628e7d.
pdepend-1.0.2 (2012/02/15)
==========================
This release contains a huge improvement in PHP_Depend's memory usage.
Due to some changes in the caching behavior we got a memory reduction
of ~ 90%, measured against medium sized code bases like Symfony2 or
FLOW3.
- Fixed #24732243: pdepend fails on 'const' Fixed in commit #4d6a687.
- Fixed #24975343: PHP_Depend doesn't handle nested list expressions.
Fixed in commit #d124ef0.
- Implemented #24702477: Huge memory footprint Implemented in commit
#75c9755.
pdepend-1.0.1 (2012/02/08)
==========================
This release fixes two bugs in PHP_Depend's parser, which resulted in
uncatchable errors.
- Fixed #24635313: _parseOptionalExpression() returning null causes
exception Fixed in commit #97189b0.
- Fixed #24638569: pdepend crashes on vanilia drupal site Fixed in
commit #f20f40a.
pdepend-1.0.0 (2012/02/04)
==========================
Now that we have completed support for all the new language features
introduced with PHP 5.4, we are ready to release version 1.0.0 of
PHP_Depend. PHP_Depend can now handle traits, static closures, binary
numbers, the callable type hint and the new short array syntax. Beside
that, we have spent much effort in improving PHP_Depend's overall
performance and we got an average speed gain of ~ 15% for processing
major frameworks like Symfony2 or FLOW3, when PHP_Depend's file cache
(default setup) is used. Additionally this release closes several
minor issues in PHP_Depend.
- Fixed #18976391: PHP_Depend's file cache implementation does not
work with PHP 5.4. Fixed in commit #06ce51a.
- Fixed #18459091: PDepend task never ends, if there is an incorrect
inheritance Fixed in commit #13b5d12.
- Fixed #19875155: Implement static closures Fixed in commit #1e24a34.
- Implemented #8927307: Add support for traits Implemented in commit
#84f612e.
- Implemented #19874825: Implement the short array syntax introduced
with PHP 5.4 Implemented in commit #338bca2.
- Implemented #9069837: Implement expression lists. Implemented in
commit #bbb06c7.
- Implemented #21435399: Implement PHP 5.4 variable method names
Implemented in commit #911b6ec.
- Implemented #21408469: Implement PHP 5.4 binary number format
Implemented in commit #e3bccf1.
- Implemented #21339411: Implement PHP 5.4 callable type hint
Implemented in commit #ee5caa6.
- Implemented #21271399: Deprecate the --phpunit-xml log option
Implemented in commit #658c25c.
- Implemented #19817309: Implement PHP 5.4 array dereferencing
Implemented in commit #6dba831.
pdepend-0.10.9 (2012/01/25)
===========================
This release fixes a small issue in PHP_Depend's parser, which results
in an exception when heredoc was used as property or constant
initializer.
- Fixed #23951621: PHP_Depend fails on Heredocs and Nowdocs in
property declaration. Fixed in commit #373c478.
pdepend-0.10.8 (2012/01/24)
===========================
This release closes an issue in PHP_Depend's parser that produces
invalid package names when the source file contains a statement before
the class or interface doc comment.
- Fixed #23905939: Package gets lost when prefixed with control
structure Fixed in commit #b62bed7.
pdepend-0.10.7 (2011/12/06)
===========================
This release closes a critical bug in PHP_Depend's parser which
results in an E_FATAL. This can happen when a control structure does
not contain a body or termination token.
- E_FATAL when a control structure like if, for or foreach does not
contain a body or a termination symbol. Fixed in commit #b367a41.
pdepend-0.10.6 (2011/08/21)
===========================
This release closes a critical bug in PHP_Depend's parser that
produced false positiv error messages for classes named like 'True',
'False' or 'Null'
- Fixed #17264279: Unexpected token: True, line: 348, col: 49,
file:... Fixed in commit #5ac3e55.
pdepend-0.10.5 (2011/05/20)
===========================
This release closes two minor bugs in PHP_Depend. One incompatibility
with PHP 5.2.x versions and one bug related to PHP_Depend's log
behavior when PHP_Depend analyzes unstructured source code. This
release was published on May the 20th 2011.
- Fixed #13255437: PHP 5.2 Compatibility Issues. Fixed in commit
#8d4a095.
- Fixed #13405179: PHP Depend report is not generated if all files do
not contain a class nor a function. Fixed in commit #554ade1.
pdepend-0.10.4 (2011/04/09)
===========================
This release contains an improvement in PHP_Depend's memory
consumption. We have optimized the internal data structures in such a
way that the memory footprint was reduced by ~30%. These values were
measured for currently popular frameworks with a medium to large sized
code base. The tests were run under ubuntu with PHP 5.2.17 and PHP
5.3.6.
pdepend-0.10.3 (2011/03/02)
===========================
This release closes a critial bug in PHP_Depend's analyzer locator
code that prevents PHP_Depend from running on windows. This release
was published on March the 02th 2011.
- Fixed #10659085: Analyzer locator code does not work on windows.
Fixed in commit #0101798.
pdepend-0.10.2 (2011/02/28)
===========================
This release of PHP_Depend closes two bugs. One related to the start
and end line properties of object property nodes in the syntax tree.
The second fix closes a bug in PHP_Depend's implementation of the WMCi
metric. Beside these two fixes this release implements three minor
features, one design issue in the syntax tree api and the other two
other features are related to the new metrics CE, CA, CBO and NPM.
Additionally we have restructured PHP_Depend's directory structure
from a custom, freestyle format to a directory layout that is similar
to maven's convention. With this change we have fixed several issues
and workarounds in PHP_Depend's build process.
- Fixed #9936901: WMCi calculation is incorrect for overwritten
methods. Fixed in commit #69d079a.
- Fixed #8927377: Invalid Start/End Line/Column for object property
access. Fixed in commit #fc57264.
- Implemented #9069393: Replace optional NULL argument of setPackage()
with separate method. Implemented in commit #1282cdb.
- Implemented #9069871: Implement efferent- and afferent-coupling for
classes. Implemented in commit #07537c2.
- Implemented #9997915: Implement Number of Public Methods metric.
Implemented in commit #2dd3ebf.
pdepend-0.10.1 (2011/02/06)
===========================
- Fixed #9634613: Notice: Undefined property $___temp___. Fixed in
commit #5fb6900.
pdepend-0.10.0 (2011/02/05)
===========================
This version only contains a small bugfix compared to the last release
canditate. Version 0.10.0 of PHP_Depend was released on February the
05th 2011. The key feature for this release is the overall performance
of PHP_Depend. Therefore we have implemented a new caching layer that
reuses already calculated analyzes-results much more efficient than
older versions of PHP_Depend. With these modifications we have
achieved a performance gain of 100% and more for consecutive
analysis-runs. This final release only fixes a small bug in
PHP_Depend's analyzer class locator that has caused some issues when
PHP_Depend was executed as an external dependency that uses a \*.phar
archive as distribution format.
- Fixed #9623949: Also find analyzers in phar archives in the current
include_path. Fixed in commit #f53dca9.
- Fixed #113: PHP fatal error when an unserialized object graph none
NodeI instances. Fixed in commit #c0f4384.
- Fixed #164: Faulty implementation of the --ignore path filter fixed.
Now this filter only works on the local part of a file or directory
name and not on the complete path. Fixed in commit #f75275e.
- Fixed #176: Calculation of CIS metric is incorrect. Fixed in commit
#1193f4a.
- Fixed #182: Clone is a valid function, method and type name in older
php versions. Fixed with git commit Fixed in commit #b18bf37.
- Fixed #189: Invalid Start/End Line/Column for object method
invocation. Fixed in commit #c6cc9dd.
- Fixed #191: New implementation of --ignore only accepts relative
paths. Fixed in commit #38e6b52.
- Fixed #163: Alternative syntax end tokens can terminate with closing
PHP-tag.
- Fixed #181: No log generated when parsing Typo3 extension
"t3extplorer" (Unexpected token ASCII 39). Indirectly fixed in this
release.
- Implemented #130: Simplify PHP_Depend's ASTCompoundVariable and skip
nested ASTCompoundExpression node instance.
- Implemented #131: Add new method isThis() to PHP_Depend's
ASTVariable class.
- Implemented #132: Housekeeping: Cleanup the PHP_Depend_Input package
test code.
- Implemented #139: Implement Post-/Pre- Increment/Decrement.
- Implemented #143: Support PHP's alternative control structure
syntax.
- Implemented #146: Implement PHP's declare-statement.
- Implemented #148: Implement cast expressions.
- Implemented #170: Rename FunctionNameParserImpl into
FunctionNameParserAllVersions. Task scope changed and complete
refactoring done. Parser moved into a version specific parser class.
- Implemented #178: Provide configuration option for the cache
directory. Implemented in commit #00ed8ec.
+29
View File
@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2008, Manuel Pichler
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+15
View File
@@ -0,0 +1,15 @@
PHP Depend
=======
[![Tests](https://github.com/pdepend/pdepend/actions/workflows/tests.yml/badge.svg)](https://github.com/pdepend/pdepend/actions/workflows/tests.yml)
[![Packagist](https://img.shields.io/packagist/dt/pdepend/pdepend.svg)](https://packagist.org/packages/pdepend/pdepend)
[![codecov](https://codecov.io/gh/pdepend/pdepend/branch/master/graph/badge.svg?token=XPgUqYrz4q)](https://codecov.io/gh/pdepend/pdepend)
[![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/pdepend/pdepend/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/pdepend/pdepend/?branch=master)
[![Chat to us on Gitter](https://badges.gitter.im/pdepend/community.svg)](https://gitter.im/pdepend/community?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
## [Documentation](https://pdepend.org/documentation/getting-started.html)
## PHP Depend for enterprise
Available as part of the Tidelift Subscription.
The maintainers of ``PHP Depend`` and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source dependencies you use to build your applications. Save time, reduce risk, and improve code health, while paying the maintainers of the exact dependencies you use. [Learn more.](https://tidelift.com/subscription/pkg/packagist-pdepend-pdepend?utm_source=packagist-pdepend-pdepend&utm_medium=referral&utm_campaign=enterprise&utm_term=repo)
+19
View File
@@ -0,0 +1,19 @@
project.dir =
project.uri = pdepend.org
project.name = pdepend
project.version = 2.16.2
project.stability = stable
project.pear.uri = pear.example.com
vendor.dir.includes = symfony/**/*,composer/**/*,autoload.php
vendor.dir.excludes = symfony/**/Tests/**/*
codesniffer.standard = PSR2
codesniffer.fail.on.violation = true
project.scm.uri = github.com/${project.name}/${project.name}/commit
phpunit.package.name = phpunit-4.8.36
phpunit.enabled = false
+45
View File
@@ -0,0 +1,45 @@
{
"name": "pdepend/pdepend",
"description": "Official version of pdepend to be handled with Composer",
"keywords": [
"dev",
"pdepend",
"PHP Depend",
"PHP_Depend"
],
"license": "BSD-3-Clause",
"type": "library",
"require": {
"php": ">=5.3.7",
"symfony/config": "^2.3.0|^3|^4|^5|^6.0|^7.0",
"symfony/dependency-injection": "^2.3.0|^3|^4|^5|^6.0|^7.0",
"symfony/filesystem": "^2.3.0|^3|^4|^5|^6.0|^7.0",
"symfony/polyfill-mbstring": "^1.19"
},
"require-dev": {
"squizlabs/php_codesniffer": "^2.0.0",
"gregwar/rst": "^1.0",
"easy-doc/easy-doc": "0.0.0|^1.2.3"
},
"bin": ["src/bin/pdepend"],
"autoload": {
"psr-4": {"PDepend\\": "src/main/php/PDepend"}
},
"scripts": {
"test": "php src/test/php/PDepend/install-test-vendor.php && php src/test/vendor/bin/phpunit --no-coverage",
"cs-check": "phpcs -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 ./src/main/php ./src/test/php",
"cs-fix": "phpcbf -p --standard=PSR2 --runtime-set ignore_errors_on_exit 1 --runtime-set ignore_warnings_on_exit 1 ./src/main/php ./src/test/php",
"build-website": [
"php src/site/release-news-generator.php",
"easy-doc build src/site/config.php --verbose"
]
},
"extra": {
"branch-alias": {
"dev-master": "2.x-dev"
}
},
"config": {
"process-timeout": 900
}
}
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0"?>
<ruleset name="PHP_Depend">
<description>Coding standard for PDepend.</description>
<file>scripts</file>
<file>src</file>
<!-- Website content -->
<exclude-pattern>src/site/</exclude-pattern>
<!-- Files for unit tests -->
<exclude-pattern>src/test/resources/</exclude-pattern>
<arg name="colors"/>
<arg value="np"/>
<rule ref="PSR2"/>
</ruleset>
+72
View File
@@ -0,0 +1,72 @@
#!/usr/bin/env php
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
use PDepend\TextUI\Command;
// PEAR/svn workaround
if (strpos('@php_bin@', '@php_bin') === 0) {
set_include_path('.' . PATH_SEPARATOR . dirname(__FILE__) . '/../main/php');
}
// check for pdepend installed as composer package
if (file_exists(__DIR__ . '/../../../../autoload.php')) {
require_once __DIR__ . '/../../../../autoload.php';
} else {
require_once __DIR__ . '/../../vendor/autoload.php';
}
// Allow as much memory as possible by default
if (extension_loaded('suhosin') && is_numeric(ini_get('suhosin.memory_limit'))) {
$limit = ini_get('memory_limit');
if (preg_match('(^(\d+)([BKMGT]))', $limit, $match)) {
$shift = array('B' => 0, 'K' => 10, 'M' => 20, 'G' => 30, 'T' => 40);
$limit = ($match[1] * (1 << $shift[$match[2]]));
}
if (ini_get('suhosin.memory_limit') > $limit && $limit > -1) {
ini_set('memory_limit', ini_get('suhosin.memory_limit'));
}
} else {
ini_set('memory_limit', -1);
}
exit(Command::main());
+46
View File
@@ -0,0 +1,46 @@
@echo off
REM This file is part of PDepend.
REM
REM Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
REM All rights reserved.
REM
REM Redistribution and use in source and binary forms, with or without
REM modification, are permitted provided that the following conditions
REM are met:
REM
REM * Redistributions of source code must retain the above copyright
REM notice, this list of conditions and the following disclaimer.
REM
REM * Redistributions in binary form must reproduce the above copyright
REM notice, this list of conditions and the following disclaimer in
REM the documentation and/or other materials provided with the
REM distribution.
REM
REM * Neither the name of Manuel Pichler nor the names of his
REM contributors may be used to endorse or promote products derived
REM from this software without specific prior written permission.
REM
REM THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
REM "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
REM LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
REM FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
REM COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
REM INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
REM BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
REM LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
REM CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRIC
REM LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
REM ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
REM POSSIBILITY OF SUCH DAMAGE.
REM
REM $Id$
REM
if "%PHPBIN%" == "" set PHPBIN=@php_bin@
if not exist "%PHPBIN%" if "%PHP_PEAR_PHP_BIN%" neq "" goto USE_PEAR_PATH
GOTO RUN
:USE_PEAR_PATH
set PHPBIN=%PHP_PEAR_PHP_BIN%
:RUN
"%PHPBIN%" "@bin_dir@\pdepend" %*
+67
View File
@@ -0,0 +1,67 @@
#!/usr/bin/env php
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
use PDepend\TextUI\Command;
// PEAR/svn workaround
if (strpos('@php_bin@', '@php_bin') === 0) {
set_include_path('.' . PATH_SEPARATOR . dirname(__FILE__) . '/../main/php');
}
require_once __DIR__ . '/../../vendor/autoload.php';
// Allow as much memory as possible by default
if (extension_loaded('suhosin') && is_numeric(ini_get('suhosin.memory_limit'))) {
$limit = ini_get('memory_limit');
if (preg_match('(^(\d+)([BKMGT]))', $limit, $match)) {
$shift = array('B' => 0, 'K' => 10, 'M' => 20, 'G' => 30, 'T' => 40);
$limit = ($match[1] * (1 << $shift[$match[2]]));
}
if (ini_get('suhosin.memory_limit') > $limit && $limit > -1) {
ini_set('memory_limit', ini_get('suhosin.memory_limit'));
}
} else {
ini_set('memory_limit', -1);
}
exit(Command::main());
@@ -0,0 +1,72 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
// <AbstractConfiguration>
/**
* This is the class that validates and merges configuration
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @codeCoverageIgnore
*/
abstract class AbstractConfiguration implements ConfigurationInterface
{
/**
* @var TreeBuilderFactory
*/
protected $treeBuilderFactory;
/**
* {@inheritDoc}
*/
public function getConfigTreeBuilder(): TreeBuilder
{
return $this->treeBuilderFactory->getConfigTreeBuilder();
}
}
// </AbstractConfiguration>
@@ -0,0 +1,71 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use Symfony\Component\Config\Definition\ConfigurationInterface;
// <AbstractConfiguration>
/**
* This is the class that validates and merges configuration
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @codeCoverageIgnore
*/
abstract class AbstractConfiguration implements ConfigurationInterface
{
/**
* @var TreeBuilderFactory
*/
protected $treeBuilderFactory;
/**
* {@inheritDoc}
*/
public function getConfigTreeBuilder()
{
return $this->treeBuilderFactory->getConfigTreeBuilder();
}
}
// </AbstractConfiguration>
@@ -0,0 +1,215 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend;
use InvalidArgumentException;
use PDepend\DependencyInjection\PdependExtension;
use PDepend\Metrics\AnalyzerFactory;
use PDepend\Report\ReportGeneratorFactory;
use PDepend\TextUI\Runner;
use PDepend\Util\Configuration;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
use Symfony\Component\DependencyInjection\TaggedContainerInterface;
/**
* PDepend Application
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Application
{
/**
* @var TaggedContainerInterface|null
**/
private $container;
/**
* @var string
*/
private $configurationFile;
/**
* @param string $configurationFile
*
* @return void
*/
public function setConfigurationFile($configurationFile)
{
if (!file_exists($configurationFile)) {
throw new InvalidArgumentException(
sprintf('The configuration file "%s" doesn\'t exist.', $configurationFile)
);
}
$this->configurationFile = $configurationFile;
}
/**
* @return Configuration
*/
public function getConfiguration()
{
return $this->getContainer()->get('pdepend.configuration');
}
/**
* @return Engine
*/
public function getEngine()
{
return $this->getContainer()->get('pdepend.engine');
}
/**
* @return Runner
*/
public function getRunner()
{
return $this->getContainer()->get('pdepend.textui.runner'); // TODO: Use standard name? textui is detail.
}
/**
* @return ReportGeneratorFactory
*/
public function getReportGeneratorFactory()
{
return $this->getContainer()->get('pdepend.report_generator_factory');
}
/**
* @return AnalyzerFactory
*/
public function getAnalyzerFactory()
{
return $this->getContainer()->get('pdepend.analyzer_factory');
}
/**
* @return TaggedContainerInterface
*/
private function getContainer()
{
if ($this->container === null) {
$this->container = $this->createContainer();
}
return $this->container;
}
/**
* @return TaggedContainerInterface
*/
private function createContainer()
{
$extensions = array(new PdependExtension());
$container = new ContainerBuilder(new ParameterBag(array()));
$container->prependExtensionConfig('pdepend', array());
$container->addCompilerPass(new DependencyInjection\Compiler\ProcessListenerPass());
$loader = new XmlFileLoader($container, new FileLocator(__DIR__ . '/../../../resources'));
foreach ($extensions as $extension) {
$container->registerExtension($extension);
}
if ($this->configurationFile) {
$loader->load($this->configurationFile);
}
$container->compile();
return $container;
}
/**
* Returns available logger options and documentation messages.
*
* @return array<string, array<string, string>>
*/
public function getAvailableLoggerOptions()
{
return $this->getAvailableOptionsFor('pdepend.logger');
}
/**
* Returns available analyzer options and documentation messages.
*
* @return array<string, array<string, string>>
*/
public function getAvailableAnalyzerOptions()
{
return $this->getAvailableOptionsFor('pdepend.analyzer');
}
/**
* @param string $serviceTag
*
* @return array<string, array<string, string>>
*/
private function getAvailableOptionsFor($serviceTag)
{
$container = $this->getContainer();
$loggerServices = $container->findTaggedServiceIds($serviceTag);
$options = array();
foreach ($loggerServices as $loggerServiceTags) {
foreach ($loggerServiceTags as $loggerServiceTag) {
if (isset($loggerServiceTag['option']) && isset($loggerServiceTag['message'])) {
$options[$loggerServiceTag['option']] = array(
'message' => $loggerServiceTag['message'],
'value' => isset($loggerServiceTag['value']) ? $loggerServiceTag['value'] : 'file'
);
}
}
}
return $options;
}
}
@@ -0,0 +1,204 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DbusUI;
// This is just fun and it is not really testable
// @codeCoverageIgnoreStart
use Dbus;
use DBusArray;
use DBusDict;
use DBusUInt32;
use PDepend\Metrics\Analyzer;
use PDepend\ProcessListener;
use PDepend\Source\ASTVisitor\AbstractASTVisitListener;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Tokenizer\Tokenizer;
/**
* Fun result printer that uses dbus to show a notification window.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ResultPrinter extends AbstractASTVisitListener implements ProcessListener
{
/**
* Time when it the process has started.
*
* @var int
*/
private $startTime = 0;
/**
* Number of parsed/analyzed files.
*
* @var int
*/
private $parsedFiles = 0;
/**
* Is called when PDepend starts the file parsing process.
*
* @param Builder<mixed> $builder The used node builder instance.
*
* @return void
*/
public function startParseProcess(Builder $builder)
{
$this->startTime = time();
}
/**
* Is called when PDepend has finished the file parsing process.
*
* @param Builder<mixed> $builder The used node builder instance.
*
* @return void
*/
public function endParseProcess(Builder $builder)
{
}
/**
* Is called when PDepend starts parsing of a new file.
*
* @return void
*/
public function startFileParsing(Tokenizer $tokenizer)
{
}
/**
* Is called when PDepend has finished a file.
*
* @return void
*/
public function endFileParsing(Tokenizer $tokenizer)
{
++$this->parsedFiles;
}
/**
* Is called when PDepend starts the analyzing process.
*
* @return void
*/
public function startAnalyzeProcess()
{
}
/**
* Is called when PDepend has finished the analyzing process.
*
* @return void
*/
public function endAnalyzeProcess()
{
}
/**
* Is called when PDepend starts the logging process.
*
* @return void
*/
public function startLogProcess()
{
}
/**
* Is called when PDepend has finished the logging process.
*
* @return void
*/
public function endLogProcess()
{
if (extension_loaded('dbus') === false) {
return;
}
$dbus = new Dbus(Dbus::BUS_SESSION);
$proxy = $dbus->createProxy(
"org.freedesktop.Notifications", // connection name
"/org/freedesktop/Notifications", // object
"org.freedesktop.Notifications" // interface
);
$proxy->Notify(
'PDepend',
new DBusUInt32(0),
'pdepend',
'PDepend',
sprintf(
'%d files analyzed in %s minutes...',
$this->parsedFiles,
(date('i:s', time() - $this->startTime))
),
new DBusArray(DBus::STRING, array()),
new DBusDict(DBus::VARIANT, array()),
1000
);
}
/**
* Is called when PDepend starts a new analyzer.
*
* @param Analyzer $analyzer The context analyzer instance.
*
* @return void
*/
public function startAnalyzer(Analyzer $analyzer)
{
}
/**
* Is called when PDepend has finished one analyzing process.
*
* @param Analyzer $analyzer The context analyzer instance.
*
* @return void
*/
public function endAnalyzer(Analyzer $analyzer)
{
}
}
// @codeCoverageIgnoreEnd
@@ -0,0 +1,72 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection\Compiler;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
/**
* Find Process Listeners of extensions by 'pdepend.process_listener' tag.
*
* Listeners are added to the PDepend\Engine service.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ProcessListenerPass implements CompilerPassInterface
{
/**
* @return void
*/
public function process(ContainerBuilder $container)
{
$engineDefinition = $container->findDefinition('pdepend.engine');
$processListenerTags = $container->findTaggedServiceIds('pdepend.process_listener');
foreach ($processListenerTags as $id => $tags) {
$engineDefinition->addMethodCall('addProcessListener', array(new Reference($id)));
}
}
}
@@ -0,0 +1,86 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use Exception;
use ReflectionMethod;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
// <AbstractConfiguration>
// @codeCoverageIgnoreStart
if (!class_exists('PDepend\\DependencyInjection\\AbstractConfiguration')) {
$typingMode = 'weak';
try {
$method = new ReflectionMethod(
'Symfony\\Component\\Config\\Definition\\ConfigurationInterface',
'getConfigTreeBuilder'
);
if (method_exists($method, 'hasReturnType') && $method->hasReturnType()) {
$typingMode = 'strong';
}
} catch (Exception $exception) {
// keep "weak"
}
require_once __DIR__ . '/../../Lazy/PDepend/DependencyInjection/Configuration.' . $typingMode . '.php';
}
// @codeCoverageIgnoreEnd
// </AbstractConfiguration>
/**
* @see ConfigurationInterface
* @see TreeBuilder
*/
class Configuration extends AbstractConfiguration
{
/**
* @param array<Extension> $extensions
*/
public function __construct(array $extensions)
{
$this->treeBuilderFactory = new TreeBuilderFactory($extensions);
}
}
@@ -0,0 +1,139 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use ReflectionClass;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Compiler\CompilerPassInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Loader\XmlFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
/**
* PDepend base extension class.
*
* Copied from Behat
*
* @link https://github.com/Behat/Behat/blob/3.0/src/Behat/Behat/Extension/Extension.php
*
* @author Konstantin Kudryashov <ever.zet@gmail.com>
*/
abstract class Extension
{
/**
* Return name of the extension
*
* @return string
*/
abstract public function getName();
/**
* Loads a specific configuration.
*
* @param array<mixed> $config Extension configuration hash (from behat.yml)
* @param ContainerBuilder $container ContainerBuilder instance
*
* @return void
*/
public function load(array $config, ContainerBuilder $container)
{
$path = rtrim($this->getServiceDefinitionsPath(), DIRECTORY_SEPARATOR);
$name = $this->getServiceDefinitionsName();
if (file_exists($path . DIRECTORY_SEPARATOR . ($file = $name . '.xml'))) {
$loader = new XmlFileLoader($container, new FileLocator($path));
$loader->load($file);
}
if (file_exists($path . DIRECTORY_SEPARATOR . ($file = $name . '.yml'))) {
$loader = new YamlFileLoader($container, new FileLocator($path));
$loader->load($file);
}
$container->setParameter($this->getName() . '.parameters', $config);
}
/**
* Setups configuration for current extension.
*
* @return void
*/
public function getConfig(ArrayNodeDefinition $builder)
{
$builder
->useAttributeAsKey('name')
->prototype('variable');
}
/**
* Returns compiler passes used by this extension.
*
* @return CompilerPassInterface[]
*/
public function getCompilerPasses()
{
return array();
}
/**
* Returns name of the service definition config without extension and path.
*
* @return string
*/
protected function getServiceDefinitionsName()
{
return 'services';
}
/**
* Returns service definition configs path.
*
* @return string
*/
protected function getServiceDefinitionsPath()
{
$reflection = new ReflectionClass($this);
return dirname($reflection->getFileName());
}
}
@@ -0,0 +1,100 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use RuntimeException;
/**
* Manage activation and registration of extensions for PDepend.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ExtensionManager
{
/**
* @var array<Extension>
*/
private $extensions = array();
/**
* Activate an extension based on a class name.
*
* @param class-string<Extension> $className
*
* @throws RuntimeException
*
* @return void
*/
public function activateExtension($className)
{
if (!class_exists($className)) {
throw new RuntimeException(
sprintf(
'Cannot find extension class "%s" for PDepend. Maybe the plugin is not installed?',
$className
)
);
}
$extension = new $className;
if (!($extension instanceof Extension)) {
throw new RuntimeException(
sprintf('Class "%s" is not a valid Extension', $className)
);
}
$this->extensions[$extension->getName()] = $extension;
}
/**
* Return all activated extensions.
*
* @return array<Extension>
*/
public function getActivatedExtensions()
{
return $this->extensions;
}
}
@@ -0,0 +1,137 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use stdClass;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\Extension as SymfonyExtension;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
/**
* PDepend DependencyInjection Extension for Symfony DIC
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class PdependExtension extends SymfonyExtension
{
/**
* @param array<array<array<array<string>>>> $configs
*
* @return void
* {@inheritDoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$extensionManager = new ExtensionManager();
foreach ($configs as $config) {
if (!isset($config['extensions'])) {
continue;
}
foreach ($config['extensions'] as $config) {
if (!isset($config['class'])) {
continue;
}
$extensionManager->activateExtension($config['class']);
}
}
$configuration = new Configuration($extensionManager->getActivatedExtensions());
$config = $this->processConfiguration($configuration, $configs);
$loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../../../resources'));
$loader->load('services.xml');
foreach ($extensionManager->getActivatedExtensions() as $extension) {
$extensionConfig = $config['extensions'][$extension->getName()];
$tempContainer = new ContainerBuilder(new ParameterBag(array()));
$tempContainer->addObjectResource($extension);
// load extension into temporary container
$extension->load($extensionConfig, $tempContainer);
// merge temporary container into normal one
$container->merge($tempContainer);
}
$settings = $this->createSettings($config);
$configurationDefinition = $container->findDefinition('pdepend.configuration');
$configurationDefinition->setArguments(array($settings));
}
/**
* @param array<string, array<string, string>> $config
*
* @return stdClass
*/
private function createSettings($config)
{
$settings = new stdClass();
$settings->cache = new stdClass();
$settings->cache->driver = $config['cache']['driver'];
$settings->cache->location = $config['cache']['location'];
$settings->cache->ttl = $config['cache']['ttl'];
$settings->imageConvert = new stdClass();
$settings->imageConvert->fontSize = $config['image_convert']['font_size'];
$settings->imageConvert->fontFamily = $config['image_convert']['font_family'];
$settings->parser = new stdClass();
$settings->parser->nesting = $config['parser']['nesting'];
return $settings;
}
public function getNamespace()
{
return 'http://pdepend.org/schema/dic/pdepend';
}
}
@@ -0,0 +1,106 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder as BaseTreeBuilder;
/**
* This is the class that embed the Symfony TreeBuilder and its root node.
*/
class TreeBuilder
{
/**
* @var ArrayNodeDefinition|NodeDefinition
*/
protected $rootNode;
/**
* @var BaseTreeBuilder
*/
protected $treeBuilder;
/**
* TreeBuilder constructor.
*
* @param string $name
*/
public function __construct($name = 'pdepend')
{
$this->treeBuilder = new BaseTreeBuilder($name);
if (method_exists($this->treeBuilder, 'getRootNode')) {
$this->rootNode = $this->treeBuilder->getRootNode();
return;
}
// @codeCoverageIgnoreStart
if (method_exists($this->treeBuilder, 'root')) {
// Symfony < 4.2
$this->rootNode = $this->treeBuilder->root($name);
}
// @codeCoverageIgnoreEnd
}
/**
* Get the root node of the built tree.
*
* @return ArrayNodeDefinition|NodeDefinition
*/
public function getRootNode()
{
return $this->rootNode;
}
/**
* Get the base Symfony tree builder.
*
* @return BaseTreeBuilder
*/
public function getTreeBuilder()
{
return $this->treeBuilder;
}
}
@@ -0,0 +1,117 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\DependencyInjection;
use PDepend\Util\FileUtil;
use PDepend\Util\Workarounds;
use Symfony\Component\Config\Definition\Builder\ArrayNodeDefinition;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
/**
* This is the class that validates and merges configuration
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class TreeBuilderFactory
{
const DEFAULT_TTL = 2592000; //30 days
/**
* @var array<Extension>
*/
private $extensions = array();
/**
* @param array<Extension> $extensions
*/
public function __construct(array $extensions)
{
$this->extensions = $extensions;
}
/**
* Generates the configuration tree builder.
*
* @return TreeBuilder
*/
public function getConfigTreeBuilder()
{
$home = FileUtil::getUserHomeDirOrSysTempDir();
$workarounds = new Workarounds();
$defaultCacheDriver = ($workarounds->hasSerializeReferenceIssue()) ? 'memory' : 'file';
$name = 'pdepend';
$treeBuilder = new TreeBuilder($name);
// @codeCoverageIgnoreStart
/** @var ArrayNodeDefinition $rootNode */
$rootNode = method_exists($treeBuilder, 'getRootNode')
? $treeBuilder->getRootNode()
: $treeBuilder->root($name); // @phpstan-ignore-line
// @codeCoverageIgnoreEnd
$nodes = $rootNode->children();
$cacheNode = $nodes->arrayNode('cache')->addDefaultsIfNotSet()->children();
$cacheNode->enumNode('driver')->defaultValue($defaultCacheDriver)->values(array('file', 'memory'));
$cacheNode->scalarNode('location')->info('This value is only used for the file cache.')->defaultValue($home . '/.pdepend');
$cacheNode->integerNode('ttl')->info('This value is only used for the file cache. Value in seconds.')->defaultValue(self::DEFAULT_TTL);
$imageConvertNode = $nodes->arrayNode('image_convert')->addDefaultsIfNotSet()->children();
$imageConvertNode->scalarNode('font_size')->defaultValue('11');
$imageConvertNode->scalarNode('font_family')->defaultValue('Arial');
$parserNode = $nodes->arrayNode('parser')->addDefaultsIfNotSet()->children();
$parserNode->integerNode('nesting')->defaultValue(65536);
$extensionsNode = $nodes->arrayNode('extensions')->addDefaultsIfNotSet()->children();
foreach ($this->extensions as $extension) {
$extensionNode = $extensionsNode->arrayNode($extension->getName());
$extension->getConfig($extensionNode);
}
return $treeBuilder;
}
}
@@ -0,0 +1,757 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend;
use AppendIterator;
use ArrayIterator;
use GlobIterator;
use InvalidArgumentException;
use OutOfBoundsException;
use PDepend\Input\CompositeFilter;
use PDepend\Input\Filter;
use PDepend\Input\Iterator;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\AnalyzerCacheAware;
use PDepend\Metrics\AnalyzerFactory;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\ReportGenerator;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTArtifactList\ArtifactFilter;
use PDepend\Source\AST\ASTArtifactList\CollectionArtifactFilter;
use PDepend\Source\AST\ASTArtifactList\NullArtifactFilter;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Language\PHP\PHPBuilder;
use PDepend\Source\Language\PHP\PHPParserGeneric;
use PDepend\Source\Language\PHP\PHPTokenizerInternal;
use PDepend\Source\Parser\ParserException;
use PDepend\Source\Tokenizer\Tokenizer;
use PDepend\Util\Cache\CacheFactory;
use PDepend\Util\Configuration;
use RecursiveDirectoryIterator;
use RecursiveIteratorIterator;
use RuntimeException;
use SplFileObject;
/**
* PDepend analyzes php class files and generates metrics.
*
* The PDepend is a php port/adaption of the Java class file analyzer
* <a href="http://clarkware.com/software/JDepend.html">JDepend</a>.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Engine
{
/**
* Marks the storage used for runtime tokens.
*/
const TOKEN_STORAGE = 1;
/**
* Marks the storag engine used for parser artifacts.
*/
const PARSER_STORAGE = 2;
/**
* The system configuration.
*
* @var Configuration
*
* @since 0.10.0
*/
protected $configuration = null;
/**
* Prefix for PHP streams.
*
* @var string
*/
protected $phpStreamPrefix = 'php://';
/**
* List of source directories.
*
* @var array<string>
*/
private $directories = array();
/**
* List of source code file names.
*
* @var array<string>
*/
private $files = array();
/**
* The used code node builder.
*
* @var PHPBuilder<ASTNamespace>|null
*/
private $builder = null;
/**
* Generated {@link ASTNamespace} objects.
*
* @var ASTArtifactList<ASTNamespace>
*/
private $namespaces = null;
/**
* List of all registered {@link ReportGenerator} instances.
*
* @var ReportGenerator[]
*/
private $generators = array();
/**
* A composite filter for input files.
*
* @var CompositeFilter
*/
private $fileFilter = null;
/**
* A filter for namespace.
*
* @var ArtifactFilter
*/
private $codeFilter = null;
/**
* Should the parse ignore doc comment annotations?
*
* @var bool
*/
private $withoutAnnotations = false;
/**
* List or registered listeners.
*
* @var ProcessListener[]
*/
private $listeners = array();
/**
* List of analyzer options.
*
* @var array<string, mixed>
*/
private $options = array();
/**
* List of all {@link ParserException} that were caught during
* the parsing process.
*
* @var ParserException[]
*/
private $parseExceptions = array();
/**
* The configured cache factory.
*
* @var CacheFactory
*
* @since 1.0.0
*/
private $cacheFactory;
/**
* @var AnalyzerFactory
*/
private $analyzerFactory;
/**
* Constructs a new php depend facade.
*
* @param Configuration $configuration The system configuration.
*/
public function __construct(
Configuration $configuration,
CacheFactory $cacheFactory,
AnalyzerFactory $analyzerFactory
) {
$this->configuration = $configuration;
$this->codeFilter = new NullArtifactFilter();
$this->fileFilter = new CompositeFilter();
$this->cacheFactory = $cacheFactory;
$this->analyzerFactory = $analyzerFactory;
}
/**
* Adds the specified directory to the list of directories to be analyzed.
*
* @param string $directory The php source directory.
*
* @return void
*/
public function addDirectory($directory)
{
$dir = realpath($directory);
if ($dir === false || !is_dir($dir)) {
throw new InvalidArgumentException("Invalid directory '{$directory}' added.");
}
$this->directories[] = $dir;
}
/**
* Adds a single source code file to the list of files to be analysed.
*
* @param string $file The source file name.
*
* @return void
*/
public function addFile($file)
{
if ($file === '-') {
$file = $this->phpStreamPrefix . 'stdin';
}
if ($this->isPhpStream($file)) {
$this->files[] = $file;
return;
}
$realPath = realpath($file);
if (!$realPath || !is_file($file)) {
throw new InvalidArgumentException(sprintf('The given file "%s" does not exist.', $file));
}
$this->files[] = $realPath;
}
/**
* Adds a logger to the output list.
*
* @param ReportGenerator $generator The logger instance.
*
* @return void
*/
public function addReportGenerator(Report\ReportGenerator $generator)
{
$this->generators[] = $generator;
}
/**
* Adds a new input/file filter.
*
* @param Filter $filter New input/file filter instance.
*
* @return void
*/
public function addFileFilter(Filter $filter)
{
$this->fileFilter->append($filter);
}
/**
* Sets an additional code filter. These filters could be used to hide
* external libraries and global stuff from the PDepend output.
*
* @return void
*/
public function setCodeFilter(ArtifactFilter $filter)
{
$this->codeFilter = $filter;
}
/**
* Sets analyzer options.
*
* @param array<string, mixed> $options The analyzer options.
*
* @return void
*/
public function setOptions(array $options = array())
{
$this->options = $options;
}
/**
* Should the parse ignore doc comment annotations?
*
* @return void
*/
public function setWithoutAnnotations()
{
$this->withoutAnnotations = true;
}
/**
* Adds a process listener.
*
* @param ProcessListener $listener The listener instance.
*
* @return void
*/
public function addProcessListener(ProcessListener $listener)
{
if (in_array($listener, $this->listeners, true) === false) {
$this->listeners[] = $listener;
}
}
/**
* Analyzes the registered directories and returns the collection of
* analyzed namespace.
*
* @return ASTArtifactList<ASTNamespace>
*/
public function analyze()
{
$this->builder = new PHPBuilder();
$this->performParseProcess();
// Get global filter collection
$collection = CollectionArtifactFilter::getInstance();
$collection->setFilter($this->codeFilter);
$collection->setFilter();
$this->performAnalyzeProcess();
// Set global filter for logging
$collection->setFilter($this->codeFilter);
$namespaces = $this->builder->getNamespaces();
$this->fireStartLogProcess();
foreach ($this->generators as $generator) {
// Check for code aware loggers
if ($generator instanceof CodeAwareGenerator) {
$generator->setArtifacts($namespaces);
}
$generator->close();
}
$this->fireEndLogProcess();
return ($this->namespaces = $namespaces);
}
/**
* Returns the number of analyzed php classes and interfaces.
*
* @return int
*/
public function countClasses()
{
if ($this->namespaces === null) {
$msg = 'countClasses() doesn\'t work before the source was analyzed.';
throw new RuntimeException($msg);
}
$classes = 0;
foreach ($this->namespaces as $namespace) {
$classes += count($namespace->getTypes());
}
return $classes;
}
/**
* Returns an <b>array</b> with all {@link ParserException}
* that were caught during the parsing process.
*
* @return ParserException[]
*/
public function getExceptions()
{
return $this->parseExceptions;
}
/**
* Returns the number of analyzed namespaces.
*
* @return int
*/
public function countNamespaces()
{
if ($this->namespaces === null) {
$msg = 'countNamespaces() doesn\'t work before the source was analyzed.';
throw new RuntimeException($msg);
}
$count = 0;
foreach ($this->namespaces as $namespace) {
if ($namespace->isUserDefined()) {
++$count;
}
}
return $count;
}
/**
* Returns the analyzed namespace for the given name.
*
* @param string $name
*
* @throws OutOfBoundsException
* @throws RuntimeException
*
* @return ASTNamespace
*/
public function getNamespace($name)
{
if ($this->namespaces === null) {
$msg = 'getNamespace() doesn\'t work before the source was analyzed.';
throw new RuntimeException($msg);
}
foreach ($this->namespaces as $namespace) {
if ($namespace->getName() === $name) {
return $namespace;
}
}
throw new OutOfBoundsException(sprintf('Unknown namespace "%s".', $name));
}
/**
* Returns an array with the analyzed namespace.
*
* @throws RuntimeException
*
* @return ASTArtifactList<ASTNamespace>
*/
public function getNamespaces()
{
if ($this->namespaces === null) {
$msg = 'getNamespaces() doesn\'t work before the source was analyzed.';
throw new RuntimeException($msg);
}
return $this->namespaces;
}
/**
* Send the start parsing process event.
*
* @param Builder<ASTNamespace> $builder The used node builder instance.
*
* @return void
*/
protected function fireStartParseProcess(Builder $builder)
{
foreach ($this->listeners as $listener) {
$listener->startParseProcess($builder);
}
}
/**
* Send the end parsing process event.
*
* @param Builder<ASTNamespace> $builder The used node builder instance.
*
* @return void
*/
protected function fireEndParseProcess(Builder $builder)
{
foreach ($this->listeners as $listener) {
$listener->endParseProcess($builder);
}
}
/**
* Sends the start file parsing event.
*
* @return void
*/
protected function fireStartFileParsing(Tokenizer $tokenizer)
{
foreach ($this->listeners as $listener) {
$listener->startFileParsing($tokenizer);
}
}
/**
* Sends the end file parsing event.
*
* @return void
*/
protected function fireEndFileParsing(Tokenizer $tokenizer)
{
foreach ($this->listeners as $listener) {
$listener->endFileParsing($tokenizer);
}
}
/**
* Sends the start analyzing process event.
*
* @return void
*/
protected function fireStartAnalyzeProcess()
{
foreach ($this->listeners as $listener) {
$listener->startAnalyzeProcess();
}
}
/**
* Sends the end analyzing process event.
*
* @return void
*/
protected function fireEndAnalyzeProcess()
{
foreach ($this->listeners as $listener) {
$listener->endAnalyzeProcess();
}
}
/**
* Sends the start log process event.
*
* @return void
*/
protected function fireStartLogProcess()
{
foreach ($this->listeners as $listener) {
$listener->startLogProcess();
}
}
/**
* Sends the end log process event.
*
* @return void
*/
protected function fireEndLogProcess()
{
foreach ($this->listeners as $listener) {
$listener->endLogProcess();
}
}
/**
* This method performs the parsing process of all source files. It expects
* that the <b>$_builder</b> property was initialized with a concrete builder
* implementation.
*
* @return void
*/
private function performParseProcess()
{
// Reset list of thrown exceptions
$this->parseExceptions = array();
$tokenizer = new PHPTokenizerInternal();
$this->fireStartParseProcess($this->builder);
foreach ($this->createFileIterator() as $file) {
$tokenizer->setSourceFile($file);
$parser = new PHPParserGeneric(
$tokenizer,
$this->builder,
$this->cacheFactory->create()
);
$parser->setMaxNestingLevel($this->configuration->parser->nesting);
// Disable annotation parsing?
if ($this->withoutAnnotations === true) {
$parser->setIgnoreAnnotations();
}
$this->fireStartFileParsing($tokenizer);
try {
$parser->parse();
} catch (ParserException $e) {
$this->parseExceptions[] = $e;
}
$this->fireEndFileParsing($tokenizer);
}
$this->fireEndParseProcess($this->builder);
}
/**
* This method performs the analysing process of the parsed source files. It
* creates the required analyzers for the registered listeners and then
* applies them to the source tree.
*
* @return void
*/
private function performAnalyzeProcess()
{
$analyzerLoader = $this->createAnalyzers($this->options);
$collection = CollectionArtifactFilter::getInstance();
$this->fireStartAnalyzeProcess();
ini_set('xdebug.max_nesting_level', $this->configuration->parser->nesting);
foreach ($analyzerLoader as $analyzer) {
// Add filters if this analyzer is filter aware
if ($analyzer instanceof AnalyzerFilterAware) {
$collection->setFilter($this->codeFilter);
}
$analyzer->analyze($this->builder->getNamespaces());
// Remove filters if this analyzer is filter aware
$collection->setFilter();
foreach ($this->generators as $logger) {
$logger->log($analyzer);
}
}
ini_restore('xdebug.max_nesting_level');
$this->fireEndAnalyzeProcess();
}
/**
* This method will create an iterator instance which contains all files
* that are part of the parsing process.
*
* @return ArrayIterator<int, string>
*/
private function createFileIterator()
{
if (count($this->directories) === 0 && count($this->files) === 0) {
throw new RuntimeException('No source directory and file set.');
}
$fileIterator = new AppendIterator();
foreach ($this->files as $file) {
$fileIterator->append(
$this->isPhpStream($file)
? new ArrayIterator(array(new SplFileObject($file)))
: new Iterator(new GlobIterator($file), $this->fileFilter)
);
}
foreach ($this->directories as $directory) {
$fileIterator->append(
new Iterator(
new RecursiveIteratorIterator(
new RecursiveDirectoryIterator(
$directory . '/',
RecursiveDirectoryIterator::FOLLOW_SYMLINKS
)
),
$this->fileFilter,
$directory
)
);
}
// TODO: It's important to validate this behavior, imho there is something
// wrong in the iterator code used above.
// Strange: why is the iterator not unique and why does this loop fix it?
$files = array();
foreach ($fileIterator as $file) {
if (is_string($file)) {
$files[$file] = $file;
} else {
$pathname = $file->getRealPath() ?: $file->getPathname();
$files[$pathname] = $pathname;
}
}
foreach ($files as $key => $file) {
if (!$this->fileFilter->accept($file, $file)) {
unset($files[$key]);
}
}
ksort($files);
// END
return new ArrayIterator(array_values($files));
}
/**
* @param array<string, mixed> $options
*
* @return Analyzer[]
*/
private function createAnalyzers($options)
{
$analyzers = $this->analyzerFactory->createRequiredForGenerators($this->generators);
$cacheKey = md5(serialize($this->files) . serialize($this->directories));
$cache = $this->cacheFactory->create($cacheKey);
foreach ($analyzers as $analyzer) {
if ($analyzer instanceof AnalyzerCacheAware) {
$analyzer->setCache($cache);
}
$analyzer->setOptions($options);
foreach ($this->listeners as $listener) {
$analyzer->addAnalyzeListener($listener);
if ($analyzer instanceof ASTVisitor) {
$analyzer->addVisitListener($listener);
}
}
}
return $analyzers;
}
/**
* @param string $path
*
* @return bool
*/
private function isPhpStream($path)
{
return substr($path, 0, strlen($this->phpStreamPrefix)) === $this->phpStreamPrefix;
}
}
@@ -0,0 +1,91 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Input;
/**
* Simple composite pattern implementation that allows to bundle multiple
* filter implementations.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class CompositeFilter implements Filter
{
/**
* List of aggregated {@link Filter} objects.
*
* @var Filter[]
*/
protected $filters = array();
/**
* Adds a file filter to this composite.
*
* @param Filter $filter The new filter object.
*
* @return void
*/
public function append(Filter $filter)
{
$this->filters[] = $filter;
}
/**
* Delegates the given <b>$localPath</b> object to all aggregated filters.
* Returns <b>true</b> if this filter accepts the given path.
*
* @param string $relative The relative path to the specified root.
* @param string $absolute The absolute path to a source file.
*
* @return bool
*/
public function accept($relative, $absolute)
{
foreach ($this->filters as $filter) {
if (false === $filter->accept($relative, $absolute)) {
return false;
}
}
return true;
}
}
@@ -0,0 +1,127 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Input;
/**
* Filters a given file path against a blacklist with disallow path fragments.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ExcludePathFilter implements Filter
{
/**
* Regular expression that should not match against the relative file paths.
*
* @var string
*
* @since 0.10.0
*/
protected $relative = '';
/**
* Regular expression that should not match against the absolute file paths.
*
* @var string
*
* @since 0.10.0
*/
protected $absolute = '';
/**
* Constructs a new exclude path filter instance and accepts an array of
* exclude pattern as argument.
*
* @param array<string> $patterns List of exclude file path patterns.
*/
public function __construct(array $patterns)
{
$quoted = array_map('preg_quote', $patterns);
$this->relative = '(' . str_replace('\*', '.*', join('|', $quoted)) . ')i';
$this->absolute = '(^(' . str_replace('\*', '.*', join('|', $quoted)) . '))i';
}
/**
* Returns <b>true</b> if this filter accepts the given path.
*
* @param string $relative The relative path to the specified root.
* @param string $absolute The absolute path to a source file.
*
* @return bool
*/
public function accept($relative, $absolute)
{
return ($this->notRelative($relative) && $this->notAbsolute($absolute));
}
/**
* This method checks if the given <b>$path</b> does not match against the
* exclude patterns as an absolute path.
*
* @param string $path The absolute path to a source file.
*
* @return bool
*
* @since 0.10.0
*/
protected function notAbsolute($path)
{
return (preg_match($this->absolute, $path) === 0);
}
/**
* This method checks if the given <b>$path</b> does not match against the
* exclude patterns as an relative path.
*
* @param string $path The relative path to a source file.
*
* @return bool
*
* @since 0.10.0
*/
protected function notRelative($path)
{
return (preg_match($this->relative, $path) === 0);
}
}
@@ -0,0 +1,89 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Input;
/**
* Whitelist filter that accepts files by their file extension.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ExtensionFilter implements Filter
{
/**
* Whitelist of accepted file extensions.
*
* @var array<string>
*/
protected $extensions = array();
/**
* Constructs a new file extension filter instance with the given list of
* allowed file <b>$extensions</b>.
*
* @param array<string> $extensions List of allowed extension.
*/
public function __construct(array $extensions)
{
$this->extensions = $extensions;
}
/**
* Returns <b>true</b> if this filter accepts the given paths.
*
* @param string $relative The relative path to the specified root.
* @param string $absolute The absolute path to a source file.
*
* @return bool
*/
public function accept($relative, $absolute)
{
if (strpos($absolute, 'php://') === 0) {
return true;
}
$extension = pathinfo($relative, PATHINFO_EXTENSION);
return in_array($extension, $this->extensions);
}
}
@@ -0,0 +1,62 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Input;
/**
* Base interface for file filters.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface Filter
{
/**
* Returns <b>true</b> if this filter accepts the given paths.
*
* @param string $relative The relative path to the specified root.
* @param string $absolute The absolute path to a source file.
*
* @return bool
*/
public function accept($relative, $absolute);
}
@@ -0,0 +1,129 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Input;
use FilterIterator;
use ReturnTypeWillChange;
use SplFileInfo;
/**
* Simple utility filter iterator for php source files.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Iterator extends FilterIterator
{
/**
* The associated filter object.
*
* @var Filter
*/
protected $filter = null;
/**
* Optional root path for the files.
*
* @var string|null
*
* @since 0.10.0
*/
protected $rootPath = null;
/**
* Constructs a new file filter iterator.
*
* @param \Iterator<SplFileInfo> $iterator The inner iterator.
* @param Filter $filter The filter object.
* @param string $rootPath Optional root path for the files.
*/
public function __construct(\Iterator $iterator, Filter $filter, $rootPath = null)
{
parent::__construct($iterator);
$this->filter = $filter;
$this->rootPath = $rootPath;
}
/**
* Returns <b>true</b> if the file name ends with '.php'.
*
* @return bool
*/
#[ReturnTypeWillChange]
public function accept()
{
if ($this->getInnerIterator()->current()->isDir()) {
return false;
}
return $this->filter->accept($this->getLocalPath(), $this->getFullPath());
}
/**
* Returns the full qualified realpath for the currently active file.
*
* @return string
*
* @since 0.10.0
*/
protected function getFullPath()
{
return $this->getInnerIterator()->current()->getRealpath();
}
/**
* Returns the local path of the current file, if the root path property was
* set. If not, this method returns the absolute file path.
*
* @return string
*
* @since 0.10.0
*/
protected function getLocalPath()
{
if ($this->rootPath && 0 === strpos($this->getFullPath(), $this->rootPath)) {
return substr($this->getFullPath(), strlen($this->rootPath));
}
return $this->getFullPath();
}
}
@@ -0,0 +1,151 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
/**
* This abstract class provides a base implementation of an analyzer.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
abstract class AbstractAnalyzer extends AbstractASTVisitor implements Analyzer
{
/**
* Global options array.
*
* @var array<string, mixed>
*/
protected $options = array();
/**
* List or registered listeners.
*
* @var AnalyzerListener[]
*/
private $listeners = array();
/**
* Constructs a new analyzer instance.
*
* @param array<string, mixed> $options Global option array, every analyzer
* can extract the required options.
*/
public function __construct(array $options = array())
{
$this->options = $options;
}
/**
* Set global options
*
* @param array<string, mixed> $options Global option array, every analyzer
* can extract the required options.
*
* @return void
*/
public function setOptions(array $options = array())
{
$this->options = $options;
}
/**
* Adds a listener to this analyzer.
*
* @param AnalyzerListener $listener The listener instance.
*
* @return void
*/
public function addAnalyzeListener(AnalyzerListener $listener)
{
if (in_array($listener, $this->listeners, true) === false) {
$this->listeners[] = $listener;
}
}
/**
* An analyzer that is active must return <b>true</b> to recognized by
* pdepend framework, while an analyzer that does not perform any action
* for any reason should return <b>false</b>.
*
* By default all analyzers are enabled. Overwrite this method to provide
* state based disabling/enabling.
*
* @return bool
*
* @since 0.9.10
*/
public function isEnabled()
{
return true;
}
/**
* The analyzer implementation should call this method when it starts the
* code processing. This method will send an analyzer start event to all
* registered listeners.
*
* @return void
*/
protected function fireStartAnalyzer()
{
foreach ($this->listeners as $listener) {
$listener->startAnalyzer($this);
}
}
/**
* The analyzer implementation should call this method when it has finished
* the code processing. This method will send an analyzer end event to all
* registered listeners.
*
* @return void
*/
protected function fireEndAnalyzer()
{
foreach ($this->listeners as $listener) {
$listener->endAnalyzer($this);
}
}
}
@@ -0,0 +1,152 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
namespace PDepend\Metrics;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Util\Cache\CacheDriver;
/**
* This abstract class provides an analyzer that provides the basic infrastructure
* for caching.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
abstract class AbstractCachingAnalyzer extends AbstractAnalyzer implements AnalyzerCacheAware
{
/**
* Collected node metrics
*
* @var array<string, mixed>
*/
protected $metrics = null;
/**
* Metrics restored from the cache. This property is only used temporary.
*
* @var array<string, mixed>
*/
private $metricsCached = array();
/**
* Injected cache driver.
*
* @var CacheDriver
*/
private $cache;
/**
* Setter method for the system wide used cache.
*
* @return void
*/
public function setCache(CacheDriver $cache)
{
$this->cache = $cache;
}
/**
* Getter method for the system wide used cache.
*
* @return CacheDriver $cache
*/
public function getCache()
{
return $this->cache;
}
/**
* Tries to restore the metrics for a cached node. If this method has
* restored the metrics it will return <b>TRUE</b>, otherwise the return
* value will be <b>FALSE</b>.
*
* @param ASTClass|ASTCompilationUnit|ASTFunction|ASTInterface|ASTMethod $node
*
* @return bool
*/
protected function restoreFromCache(AbstractASTArtifact $node)
{
$id = $node->getId();
if ($node->isCached() && isset($this->metricsCached[$id])) {
$this->metrics[$id] = $this->metricsCached[$id];
return true;
}
return false;
}
/**
* Initializes the previously calculated metrics from the cache.
*
* @return void
*/
protected function loadCache()
{
$this->metricsCached = (array) $this->cache
->type('metrics')
->restore(get_class($this));
}
/**
* Unloads the metrics cache and stores the current set of metrics in the
* cache.
*
* @return void
*/
protected function unloadCache()
{
$this->cache
->type('metrics')
->store(get_class($this), $this->metrics);
$this->metricsCached = array();
}
}
@@ -0,0 +1,70 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
/**
* This analyzer interface provides a specialized form that allows an analyzer
* to aggregate metrics calculated by other analyzers.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface AggregateAnalyzer extends Analyzer
{
/**
* This method must return an <b>array</b> of class names for required
* analyzers.
*
* @return array<string>
*/
public function getRequiredAnalyzers();
/**
* Adds a required sub analyzer.
*
* @param Analyzer $analyzer The sub analyzer instance.
*
* @return void
*/
public function addAnalyzer(Analyzer $analyzer);
}
@@ -0,0 +1,103 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTNamespace;
/**
* Base interface for all analyzer implementations.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface Analyzer
{
/**
* Constructs a new analyzer instance.
*
* @param array<string, mixed> $options Global option array, every analyzer
* can extract the required options.
*/
public function __construct(array $options = array());
/**
* Adds a listener to this analyzer.
*
* @param AnalyzerListener $listener The listener instance.
*
* @return void
*/
public function addAnalyzeListener(AnalyzerListener $listener);
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @param ASTArtifactList<ASTNamespace> $namespaces
*
* @return void
*/
public function analyze($namespaces);
/**
* An analyzer that is active must return <b>true</b> to recognized by
* pdepend framework, while an analyzer that does not perform any action
* for any reason should return <b>false</b>.
*
* @return bool
*
* @since 0.9.10
*/
public function isEnabled();
/**
* Set global options
*
* @param array<string, mixed> $options
*
* @return void
*
* @since 2.0.1
*/
public function setOptions(array $options = array());
}
@@ -0,0 +1,320 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\AbstractASTType;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
/**
* This visitor generates the metrics for the analyzed namespaces.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ClassDependencyAnalyzer extends AbstractAnalyzer
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_AFFERENT_COUPLING = 'ca',
M_EFFERENT_COUPLING = 'ce';
/**
* Hash with all calculated node metrics.
*
* @var array<string, array<string, array<string, string>>>
*/
private $nodeMetrics = null;
/**
* @var array<string, ASTNamespace>
*/
protected $nodeSet = array();
/**
* Nodes in which the current analyzed class is used.
*
* @var array<string, array<int, AbstractASTType>>
*/
private $efferentNodes = array();
/**
* Nodes that is used by the current analyzed class.
*
* @var array<string, array<int, AbstractASTType>>
*/
private $afferentNodes = array();
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->nodeMetrics === null) {
$this->fireStartAnalyzer();
$this->nodeMetrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->postProcess();
$this->fireEndAnalyzer();
}
}
/**
* Returns an array of all afferent nodes.
*
* @return AbstractASTType[]
*/
public function getAfferents(AbstractASTArtifact $node)
{
$afferents = array();
if (isset($this->afferentNodes[$node->getId()])) {
$afferents = $this->afferentNodes[$node->getId()];
}
return $afferents;
}
/**
* Returns an array of all efferent nodes.
*
* @return AbstractASTType[]
*/
public function getEfferents(AbstractASTArtifact $node)
{
$efferents = array();
if (isset($this->efferentNodes[$node->getId()])) {
$efferents = $this->efferentNodes[$node->getId()];
}
return $efferents;
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
$type = $method->getParent();
foreach ($method->getDependencies() as $dependency) {
$this->collectDependencies($type, $dependency);
}
$this->fireEndMethod($method);
}
/**
* Visits a namespace node.
*
* @return void
*/
public function visitNamespace(ASTNamespace $namespace)
{
$this->fireStartNamespace($namespace);
$this->nodeSet[$namespace->getId()] = $namespace;
foreach ($namespace->getTypes() as $type) {
$type->accept($this);
}
$this->fireEndNamespace($namespace);
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
$this->fireStartClass($class);
$this->visitType($class);
$this->fireEndClass($class);
}
/**
* Visits an interface node.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
$this->fireStartInterface($interface);
$this->visitType($interface);
$this->fireEndInterface($interface);
}
/**
* Generic visit method for classes and interfaces. Both visit methods
* delegate calls to this method.
*
* @return void
*/
protected function visitType(AbstractASTClassOrInterface $type)
{
$id = $type->getId();
foreach ($type->getDependencies() as $dependency) {
$this->collectDependencies($type, $dependency);
}
foreach ($type->getMethods() as $method) {
$method->accept($this);
}
}
/**
* Collects the dependencies between the two given classes.
*
* @return void
*/
private function collectDependencies(AbstractASTClassOrInterface $typeA, AbstractASTClassOrInterface $typeB)
{
$idA = $typeA->getId();
$idB = $typeB->getId();
if ($idB === $idA) {
return;
}
// Create a container for this dependency
$this->initTypeMetric($typeA);
$this->initTypeMetric($typeB);
if (!in_array($idB, $this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING])) {
$this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING][] = $idB;
$this->nodeMetrics[$idB][self::M_AFFERENT_COUPLING][] = $idA;
}
}
/**
* Initializes the node metric record for the given <b>$type</b>.
*
* @return void
*/
protected function initTypeMetric(AbstractASTClassOrInterface $type)
{
$id = $type->getId();
if (!isset($this->nodeMetrics[$id])) {
$this->nodeSet[$id] = $type;
$this->nodeMetrics[$id] = array(
self::M_AFFERENT_COUPLING => array(),
self::M_EFFERENT_COUPLING => array(),
);
}
}
/**
* Post processes all analyzed nodes.
*
* @return void
*/
protected function postProcess()
{
foreach ($this->nodeMetrics as $id => $metrics) {
$this->afferentNodes[$id] = array();
foreach ($metrics[self::M_AFFERENT_COUPLING] as $caId) {
$this->afferentNodes[$id][] = $this->nodeSet[$caId];
}
$this->efferentNodes[$id] = array();
foreach ($metrics[self::M_EFFERENT_COUPLING] as $ceId) {
$this->efferentNodes[$id][] = $this->nodeSet[$ceId];
}
$afferent = count($metrics[self::M_AFFERENT_COUPLING]);
$efferent = count($metrics[self::M_EFFERENT_COUPLING]);
$this->nodeMetrics[$id][self::M_AFFERENT_COUPLING] = $afferent;
$this->nodeMetrics[$id][self::M_EFFERENT_COUPLING] = $efferent;
}
}
/**
* Collects a single cycle that is reachable by this namespace. All namespaces
* that are part of the cylce are stored in the given <b>$list</b> array.
*
* @param AbstractASTArtifact[] $list
*
* @return bool If this method detects a cycle the return value is <b>true</b>
* otherwise this method will return <b>false</b>.
*/
protected function collectCycle(array &$list, AbstractASTArtifact $node)
{
if (in_array($node, $list, true)) {
$list[] = $node;
return true;
}
$list[] = $node;
foreach ($this->getEfferents($node) as $efferent) {
if ($this->collectCycle($list, $efferent)) {
return true;
}
}
if (is_int($idx = array_search($node, $list, true))) {
unset($list[$idx]);
}
return false;
}
}
@@ -0,0 +1,434 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use InvalidArgumentException;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AggregateAnalyzer;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\AbstractASTType;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTEnum;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTTrait;
use RuntimeException;
/**
* Generates some class level based metrics. This analyzer is based on the
* metrics specified in the following document.
*
* http://www.aivosto.com/project/help/pm-oo-misc.html
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ClassLevelAnalyzer extends AbstractAnalyzer implements AggregateAnalyzer, AnalyzerFilterAware, AnalyzerNodeAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_IMPLEMENTED_INTERFACES = 'impl',
M_CLASS_INTERFACE_SIZE = 'cis',
M_CLASS_SIZE = 'csz',
M_NUMBER_OF_PUBLIC_METHODS = 'npm',
M_PROPERTIES = 'vars',
M_PROPERTIES_INHERIT = 'varsi',
M_PROPERTIES_NON_PRIVATE = 'varsnp',
M_WEIGHTED_METHODS = 'wmc',
M_WEIGHTED_METHODS_INHERIT = 'wmci',
M_WEIGHTED_METHODS_NON_PRIVATE = 'wmcnp';
/**
* Hash with all calculated node metrics.
*
* <code>
* array(
* '0375e305-885a-4e91-8b5c-e25bda005438' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* ),
* 'e60c22f0-1a63-4c40-893e-ed3b35b84d0b' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* )
* )
* </code>
*
* @var array<string, array<string, int>>
*/
private $nodeMetrics = null;
/**
* The internal used cyclomatic complexity analyzer.
*
* @var CyclomaticComplexityAnalyzer
*/
private $cyclomaticAnalyzer = null;
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->nodeMetrics === null) {
// First check for the require cc analyzer
if ($this->cyclomaticAnalyzer === null) {
throw new RuntimeException('Missing required CC analyzer.');
}
$this->fireStartAnalyzer();
$this->cyclomaticAnalyzer->analyze($namespaces);
// Init node metrics
$this->nodeMetrics = array();
// Visit all nodes
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
}
}
/**
* This method must return an <b>array</b> of class names for required
* analyzers.
*
* @return array<string>
*/
public function getRequiredAnalyzers()
{
return array('PDepend\\Metrics\\Analyzer\\CyclomaticComplexityAnalyzer');
}
/**
* Adds a required sub analyzer.
*
* @param Analyzer $analyzer The sub analyzer instance.
*
* @return void
*/
public function addAnalyzer(Analyzer $analyzer)
{
if ($analyzer instanceof CyclomaticComplexityAnalyzer) {
$this->cyclomaticAnalyzer = $analyzer;
} else {
throw new InvalidArgumentException('CC Analyzer required.');
}
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b>. If there are no metrics for the requested
* node, this method will return an empty <b>array</b>.
*
* @return array<string, mixed>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
$metrics = array();
if (isset($this->nodeMetrics[$artifact->getId()])) {
$metrics = $this->nodeMetrics[$artifact->getId()];
}
return $metrics;
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
$this->fireStartClass($class);
$this->calculateAbstractASTClassOrInterfaceMetrics($class);
$this->fireEndClass($class);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
// Empty visit method, we don't want interface metrics
}
/**
* Visits a trait node.
*
* @return void
*
* @since 1.0.0
*/
public function visitTrait(ASTTrait $trait)
{
$this->fireStartTrait($trait);
$wmci = $this->calculateWmciForTrait($trait);
$this->nodeMetrics[$trait->getId()] = array(
self::M_IMPLEMENTED_INTERFACES => 0,
self::M_CLASS_INTERFACE_SIZE => 0,
self::M_CLASS_SIZE => 0,
self::M_NUMBER_OF_PUBLIC_METHODS => 0,
self::M_PROPERTIES => 0,
self::M_PROPERTIES_INHERIT => 0,
self::M_PROPERTIES_NON_PRIVATE => 0,
self::M_WEIGHTED_METHODS => 0,
self::M_WEIGHTED_METHODS_INHERIT => $wmci,
self::M_WEIGHTED_METHODS_NON_PRIVATE => 0
);
foreach ($trait->getProperties() as $property) {
$property->accept($this);
}
foreach ($trait->getMethods() as $method) {
$method->accept($this);
}
$this->fireEndTrait($trait);
}
/**
* Visits a enum node.
*
* @return void
*
* @since 2.12.1
*/
public function visitEnum(ASTEnum $enum)
{
$this->fireStartEnum($enum);
$this->calculateAbstractASTClassOrInterfaceMetrics($enum);
$this->fireEndEnum($enum);
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
$id = $method->getParent()->getId();
$ccn = $this->cyclomaticAnalyzer->getCcn2($method);
// Increment Weighted Methods Per Class(WMC) value
$this->nodeMetrics[$id][self::M_WEIGHTED_METHODS] += $ccn;
// Increment Class Size(CSZ) value
++$this->nodeMetrics[$id][self::M_CLASS_SIZE];
// Increment Non Private values
if ($method->isPublic()) {
++$this->nodeMetrics[$id][self::M_NUMBER_OF_PUBLIC_METHODS];
// Increment Non Private WMC value
$this->nodeMetrics[$id][self::M_WEIGHTED_METHODS_NON_PRIVATE] += $ccn;
// Increment Class Interface Size(CIS) value
++$this->nodeMetrics[$id][self::M_CLASS_INTERFACE_SIZE];
}
$this->fireEndMethod($method);
}
/**
* Visits a property node.
*
* @return void
*/
public function visitProperty(ASTProperty $property)
{
$this->fireStartProperty($property);
$id = $property->getDeclaringClass()->getId();
// Increment VARS value
++$this->nodeMetrics[$id][self::M_PROPERTIES];
// Increment Class Size(CSZ) value
++$this->nodeMetrics[$id][self::M_CLASS_SIZE];
// Increment Non Private values
if ($property->isPublic()) {
// Increment Non Private VARS value
++$this->nodeMetrics[$id][self::M_PROPERTIES_NON_PRIVATE];
// Increment Class Interface Size(CIS) value
++$this->nodeMetrics[$id][self::M_CLASS_INTERFACE_SIZE];
}
$this->fireEndProperty($property);
}
/**
* Calculates the Variables Inheritance of a class metric, this method only
* counts protected and public properties of parent classes.
*
* @param ASTClass|ASTEnum|ASTTrait $class The context class instance.
*
* @return int
*/
private function calculateVarsi(AbstractASTClassOrInterface $class)
{
// List of properties, this method only counts not overwritten properties
$properties = array();
// Collect all properties of the context class
foreach ($class->getProperties() as $prop) {
$properties[$prop->getName()] = true;
}
foreach ($class->getParentClasses() as $parent) {
foreach ($parent->getProperties() as $prop) {
if (!$prop->isPrivate() && !isset($properties[$prop->getName()])) {
$properties[$prop->getName()] = true;
}
}
}
return count($properties);
}
/**
* Calculates the Weight Method Per Class metric, this method only counts
* protected and public methods of parent classes.
*
* @return int
*/
private function calculateWmciForClass(AbstractASTClassOrInterface $class)
{
$ccn = $this->calculateWmci($class);
foreach ($class->getParentClasses() as $parent) {
foreach ($parent->getMethods() as $method) {
if ($method->isPrivate()) {
continue;
}
if (isset($ccn[($name = $method->getName())])) {
continue;
}
$ccn[$name] = $this->cyclomaticAnalyzer->getCcn2($method);
}
}
return array_sum($ccn);
}
/**
* Calculates the Weight Method Per Class metric for a trait.
*
* @return int
*
* @since 1.0.6
*/
private function calculateWmciForTrait(ASTTrait $trait)
{
return array_sum($this->calculateWmci($trait));
}
/**
* Calculates the Weight Method Per Class metric.
*
* @return int[]
*
* @since 1.0.6
*/
private function calculateWmci(AbstractASTType $type)
{
$ccn = array();
foreach ($type->getMethods() as $method) {
$ccn[$method->getName()] = $this->cyclomaticAnalyzer->getCcn2($method);
}
return $ccn;
}
/**
* @param ASTClass|ASTEnum $class
*
* @return void
*/
private function calculateAbstractASTClassOrInterfaceMetrics(AbstractASTClassOrInterface $class)
{
$impl = count($class->getInterfaces());
$varsi = $this->calculateVarsi($class);
$wmci = $this->calculateWmciForClass($class);
$this->nodeMetrics[$class->getId()] = array(
self::M_IMPLEMENTED_INTERFACES => $impl,
self::M_CLASS_INTERFACE_SIZE => 0,
self::M_CLASS_SIZE => 0,
self::M_NUMBER_OF_PUBLIC_METHODS => 0,
self::M_PROPERTIES => 0,
self::M_PROPERTIES_INHERIT => $varsi,
self::M_PROPERTIES_NON_PRIVATE => 0,
self::M_WEIGHTED_METHODS => 0,
self::M_WEIGHTED_METHODS_INHERIT => $wmci,
self::M_WEIGHTED_METHODS_NON_PRIVATE => 0
);
if ($class instanceof ASTClass) {
foreach ($class->getProperties() as $property) {
$property->accept($this);
}
}
foreach ($class->getMethods() as $method) {
$method->accept($this);
}
}
}
@@ -0,0 +1,234 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\Analyzer\CodeRankAnalyzer\CodeRankStrategyI;
use PDepend\Metrics\Analyzer\CodeRankAnalyzer\StrategyFactory;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTNamespace;
/**
* Calculates the code rank metric for classes and namespaces.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class CodeRankAnalyzer extends AbstractAnalyzer implements AnalyzerNodeAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_CODE_RANK = 'cr',
M_REVERSE_CODE_RANK = 'rcr';
/**
* The used damping factor.
*/
const DAMPING_FACTOR = 0.85;
/**
* Number of loops for the code range calculation.
*/
const ALGORITHM_LOOPS = 25;
/**
* Option key for the code rank mode.
*/
const STRATEGY_OPTION = 'coderank-mode';
/**
* All found nodes.
*
* @var array<string, array<string, array<int, string>>>
*/
private $nodes = array();
/**
* List of node collect strategies.
*
* @var CodeRankStrategyI[]
*/
private $strategies = array();
/**
* Hash with all calculated node metrics.
*
* <code>
* array(
* '0375e305-885a-4e91-8b5c-e25bda005438' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* ),
* 'e60c22f0-1a63-4c40-893e-ed3b35b84d0b' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* )
* )
* </code>
*
* @var array<string, array<string, int>>
*/
private $nodeMetrics = null;
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->nodeMetrics === null) {
$this->fireStartAnalyzer();
$factory = new StrategyFactory();
if (isset($this->options[self::STRATEGY_OPTION])) {
foreach ($this->options[self::STRATEGY_OPTION] as $identifier) {
$this->strategies[] = $factory->createStrategy($identifier);
}
} else {
$this->strategies[] = $factory->createDefaultStrategy();
}
// Register all listeners
foreach ($this->getVisitListeners() as $listener) {
foreach ($this->strategies as $strategy) {
$strategy->addVisitListener($listener);
}
}
foreach ($namespaces as $namespace) {
// Traverse all strategies
foreach ($this->strategies as $strategy) {
$namespace->accept($strategy);
}
}
// Collect all nodes
foreach ($this->strategies as $strategy) {
$collected = $strategy->getCollectedNodes();
$this->nodes = array_merge_recursive($collected, $this->nodes);
}
// Init node metrics
$this->nodeMetrics = array();
// Calculate code rank metrics
$this->buildCodeRankMetrics();
$this->fireEndAnalyzer();
}
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b>. If there are no metrics for the requested
* node, this method will return an empty <b>array</b>.
*
* @return array<string, mixed>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->nodeMetrics[$artifact->getId()])) {
return $this->nodeMetrics[$artifact->getId()];
}
return array();
}
/**
* Generates the forward and reverse code rank for the given <b>$nodes</b>.
*
* @return void
*/
protected function buildCodeRankMetrics()
{
foreach (array_keys($this->nodes) as $id) {
$this->nodeMetrics[$id] = array(
self::M_CODE_RANK => 0,
self::M_REVERSE_CODE_RANK => 0
);
}
foreach ($this->computeCodeRank('out', 'in') as $id => $rank) {
$this->nodeMetrics[$id][self::M_CODE_RANK] = $rank;
}
foreach ($this->computeCodeRank('in', 'out') as $id => $rank) {
$this->nodeMetrics[$id][self::M_REVERSE_CODE_RANK] = $rank;
}
}
/**
* Calculates the code rank for the given <b>$nodes</b> set.
*
* @param string $id1 Identifier for the incoming edges.
* @param string $id2 Identifier for the outgoing edges.
*
* @return array<string, float>
*/
protected function computeCodeRank($id1, $id2)
{
$dampingFactory = self::DAMPING_FACTOR;
$ranks = array();
foreach (array_keys($this->nodes) as $name) {
$ranks[$name] = 1;
}
for ($i = 0; $i < self::ALGORITHM_LOOPS; $i++) {
foreach ($this->nodes as $name => $info) {
$rank = 0;
foreach ($info[$id1] as $ref) {
$previousRank = $ranks[$ref];
$refCount = count($this->nodes[$ref][$id2]);
$rank += ($previousRank / $refCount);
}
$ranks[$name] = ((1 - $dampingFactory)) + $dampingFactory * $rank;
}
}
return $ranks;
}
}
@@ -0,0 +1,61 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* The code rank strategy provides an interface for dependency collection.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface CodeRankStrategyI extends ASTVisitor
{
/**
* Returns the collected nodes.
*
* @return array<string, array<string, array<int, string>>>
*/
public function getCollectedNodes();
}
@@ -0,0 +1,146 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
/**
* Collects class and namespace metrics based on inheritance.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class InheritanceStrategy extends AbstractASTVisitor implements CodeRankStrategyI
{
/**
* All found nodes.
*
* @var array<string, array<string, array<int, string>>>
*/
private $nodes = array();
/**
* Returns the collected nodes.
*
* @return array<string, array<string, array<int, string>>>
*/
public function getCollectedNodes()
{
return $this->nodes;
}
/**
* Visits a code class object.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
$this->fireStartClass($class);
$this->visitType($class);
$this->fireEndClass($class);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
$this->fireStartInterface($interface);
$this->visitType($interface);
$this->fireEndInterface($interface);
}
/**
* Generic visitor method for classes and interfaces. Both visit methods
* delegate calls to this method.
*
* @return void
*/
protected function visitType(AbstractASTClassOrInterface $type)
{
$namespace = $type->getNamespace();
$this->initNode($namespace);
$this->initNode($type);
foreach ($type->getDependencies() as $dependency) {
$depPkg = $dependency->getNamespace();
$this->initNode($dependency);
$this->initNode($depPkg);
$this->nodes[$type->getId()]['in'][] = $dependency->getId();
$this->nodes[$dependency->getId()]['out'][] = $type->getId();
// No self references
if ($namespace !== $depPkg) {
$this->nodes[$namespace->getId()]['in'][] = $depPkg->getId();
$this->nodes[$depPkg->getId()]['out'][] = $namespace->getId();
}
}
}
/**
* Initializes the temporary node container for the given <b>$node</b>.
*
* @return void
*/
protected function initNode(AbstractASTArtifact $node)
{
if (!isset($this->nodes[$node->getId()])) {
$this->nodes[$node->getId()] = array(
'in' => array(),
'out' => array(),
'name' => $node->getName(),
'type' => get_class($node)
);
}
}
}
@@ -0,0 +1,144 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
/**
* Collects class and namespace metrics based on class and interface methods.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class MethodStrategy extends AbstractASTVisitor implements CodeRankStrategyI
{
/**
* All found nodes.
*
* @var array<string, array<string, array<int, string>>>
*/
private $nodes = array();
/**
* Returns the collected nodes.
*
* @return array<string, array<string, array<int, string>>>
*/
public function getCollectedNodes()
{
return $this->nodes;
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
// Get owner type
$type = $method->getParent();
if (($depType = $method->getReturnClass()) !== null) {
$this->processType($type, $depType);
}
foreach ($method->getExceptionClasses() as $depType) {
$this->processType($type, $depType);
}
foreach ($method->getDependencies() as $depType) {
$this->processType($type, $depType);
}
$this->fireEndMethod($method);
}
/**
* Extracts the coupling information between the two given types and their
* parent namespacess.
*
* @return void
*/
private function processType(AbstractASTClassOrInterface $type, AbstractASTClassOrInterface $dependency)
{
if ($type !== $dependency) {
$this->initNode($type);
$this->initNode($dependency);
$this->nodes[$type->getId()]['in'][] = $dependency->getId();
$this->nodes[$dependency->getId()]['out'][] = $type->getId();
}
$namespace = $type->getNamespace();
$dependencyNamespace = $dependency->getNamespace();
if ($namespace !== $dependencyNamespace) {
$this->initNode($namespace);
$this->initNode($dependencyNamespace);
$this->nodes[$namespace->getId()]['in'][] = $dependencyNamespace->getId();
$this->nodes[$dependencyNamespace->getId()]['out'][] = $namespace->getId();
}
}
/**
* Initializes the temporary node container for the given <b>$node</b>.
*
* @return void
*/
private function initNode(AbstractASTArtifact $node)
{
if (!isset($this->nodes[$node->getId()])) {
$this->nodes[$node->getId()] = array(
'in' => array(),
'out' => array(),
'name' => $node->getName(),
'type' => get_class($node)
);
}
}
}
@@ -0,0 +1,128 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
/**
* Collects class and namespace metrics based on class properties.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class PropertyStrategy extends AbstractASTVisitor implements CodeRankStrategyI
{
/**
* All found nodes.
*
* @var array<string, array<string, array<int, string>>>
*/
private $nodes = array();
/**
* Returns the collected nodes.
*
* @return array<string, array<string, array<int, string>>>
*/
public function getCollectedNodes()
{
return $this->nodes;
}
/**
* Visits a property node.
*
* @return void
*/
public function visitProperty(ASTProperty $property)
{
$this->fireStartProperty($property);
if (($depClass = $property->getClass()) === null) {
$this->fireEndProperty($property);
return;
}
$depNamespace = $depClass->getNamespace();
$class = $property->getDeclaringClass();
$namespace = $class->getNamespace();
if ($depClass !== $class) {
$this->initNode($class);
$this->initNode($depClass);
$this->nodes[$class->getId()]['in'][] = $depClass->getId();
$this->nodes[$depClass->getId()]['out'][] = $class->getId();
}
if ($depNamespace !== $namespace) {
$this->initNode($namespace);
$this->initNode($depNamespace);
$this->nodes[$namespace->getId()]['in'][] = $depNamespace->getId();
$this->nodes[$depNamespace->getId()]['out'][] = $namespace->getId();
}
$this->fireEndProperty($property);
}
/**
* Initializes the temporary node container for the given <b>$node</b>.
*
* @return void
*/
protected function initNode(AbstractASTArtifact $node)
{
if (!isset($this->nodes[$node->getId()])) {
$this->nodes[$node->getId()] = array(
'in' => array(),
'out' => array(),
'name' => $node->getName(),
'type' => get_class($node)
);
}
}
}
@@ -0,0 +1,129 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer\CodeRankAnalyzer;
use InvalidArgumentException;
/**
* Factory for the different code rank strategies.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class StrategyFactory
{
/**
* The identifier for the inheritance strategy.
*/
const STRATEGY_INHERITANCE = 'inheritance';
/**
* The identifier for the property strategy.
*/
const STRATEGY_PROPERTY = 'property';
/**
* The identifier for the method strategy.
*/
const STRATEGY_METHOD = 'method';
/**
* The default strategy.
*
* @var string
*/
private $defaultStrategy = self::STRATEGY_INHERITANCE;
/**
* List of all valid properties.
*
* @var array<string>
*/
private $validStrategies = array(
self::STRATEGY_INHERITANCE,
self::STRATEGY_METHOD,
self::STRATEGY_PROPERTY
);
/**
* Creates the default code rank strategy.
*
* @return CodeRankStrategyI
*/
public function createDefaultStrategy()
{
return $this->createStrategy($this->defaultStrategy);
}
/**
* Creates a code rank strategy for the given identifier.
*
* @param string $strategyName The strategy identifier.
*
* @throws InvalidArgumentException If the given <b>$id</b> is not valid or
* no matching class declaration exists.
*
* @return CodeRankStrategyI
*/
public function createStrategy($strategyName)
{
if (in_array($strategyName, $this->validStrategies) === false) {
throw new InvalidArgumentException(
sprintf('Cannot load file for identifier "%s".', $strategyName)
);
}
// Prepare identifier
$name = ucfirst(strtolower($strategyName));
$className = "PDepend\\Metrics\\Analyzer\\CodeRankAnalyzer\\{$name}Strategy";
if (false === class_exists($className)) {
$fileName = "PDepend/Metrics/Analyzer/CodeRankAnalyzer/{$name}Strategy.php";
include_once $fileName;
}
return new $className();
}
}
@@ -0,0 +1,158 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTMemberPrimaryPrefix;
use PDepend\Source\AST\ASTMethodPostfix;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTProperty;
use PDepend\Source\AST\ASTPropertyPostfix;
use PDepend\Source\AST\ASTSelfReference;
use PDepend\Source\AST\ASTVariable;
/**
* This analyzer implements several metrics that describe cohesion of classes
* and namespaces.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class CohesionAnalyzer extends AbstractAnalyzer implements AnalyzerNodeAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_LCOM4 = 'lcom4';
/**
* Collected cohesion metrics for classes.
*
* @var array<string, array<string, integer>>
*/
private $nodeMetrics = array();
/**
* This method will return an <b>array</b> with all generated metric values
* for the node with the given <b>$id</b> identifier. If there are no
* metrics for the requested node, this method will return an empty <b>array</b>.
*
* <code>
* array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* )
* </code>
*
* @return array<string, integer>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->nodeMetrics[$artifact->getId()])) {
return $this->nodeMetrics[$artifact->getId()];
}
return array();
}
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
$this->fireStartAnalyzer();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
}
/*
public function visitProperty(ASTProperty $property)
{
$this->fireStartProperty($property);
echo ltrim($property->getName(), '$'), PHP_EOL;
$this->fireEndProperty($property);
}
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
$prefixes = $method->findChildrenOfType(
'PDepend\\Source\\AST\\ASTMemberPrimaryPrefix'
);
foreach ($prefixes as $prefix) {
$variable = $prefix->getChild(0);
if ($variable instanceof ASTVariable
&& $variable->isThis()
) {
echo "\$this->";
} elseif ($variable instanceof ASTSelfReference) {
echo "self::";
} else {
continue;
}
$next = $prefix->getChild(1);
if ($next instanceof ASTMemberPrimaryPrefix) {
$next = $next->getChild(0);
}
if ($next instanceof ASTPropertyPostfix) {
echo $next->getImage(), PHP_EOL;
} elseif ($next instanceof ASTMethodPostfix) {
echo $next->getImage(), '()', PHP_EOL;
}
}
$this->fireEndMethod($method);
}
*/
}
@@ -0,0 +1,456 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\AbstractASTType;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTProperty;
/**
* This analyzer collects coupling values for the hole project. It calculates
* all function and method <b>calls</b> and the <b>fanout</b>, that means the
* number of referenced types.
*
* The FANOUT calculation is based on the definition used by the apache maven
* project.
*
* <ul>
* <li>field declarations (Uses doc comment annotations)</li>
* <li>formal parameters and return types (The return type uses doc comment
* annotations)</li>
* <li>throws declarations (Uses doc comment annotations)</li>
* <li>local variables</li>
* </ul>
*
* http://www.jajakarta.org/turbine/en/turbine/maven/reference/metrics.html
*
* The implemented algorithm counts each type only once for a method and function.
* Any type that is either a supertype or a subtype of the class is not counted.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class CouplingAnalyzer extends AbstractAnalyzer implements AnalyzerNodeAware, AnalyzerProjectAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_CALLS = 'calls',
M_FANOUT = 'fanout',
M_CA = 'ca',
M_CBO = 'cbo',
M_CE = 'ce';
/**
* Has this analyzer already processed the source under test?
*
* @var bool
*
* @since 0.10.2
*/
private $uninitialized = true;
/**
* The number of method or function calls.
*
* @var int
*/
private $calls = 0;
/**
* Number of fanouts.
*
* @var int
*/
private $fanout = 0;
/**
* Temporary map that is used to hold the id combinations of dependee and
* depender.
*
* @var array<string, array<string, array<string, bool>>>
*
* @since 0.10.2
*/
private $dependencyMap = array();
/**
* This array holds a mapping between node identifiers and an array with
* the node's metrics.
*
* @var array<string, array<string, mixed>>
*
* @since 0.10.2
*/
private $nodeMetrics = array();
/**
* Provides the project summary as an <b>array</b>.
*
* <code>
* array(
* 'calls' => 23,
* 'fanout' => 42
* )
* </code>
*
* @return array<string, mixed>
*/
public function getProjectMetrics()
{
return array(
self::M_CALLS => $this->calls,
self::M_FANOUT => $this->fanout
);
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the given node instance. If there are no metrics for the given node
* this method will return an empty <b>array</b>.
*
* <code>
* array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* )
* </code>
*
* @return array<string, mixed>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->nodeMetrics[$artifact->getId()])) {
return $this->nodeMetrics[$artifact->getId()];
}
return array();
}
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->uninitialized) {
$this->doAnalyze($namespaces);
$this->uninitialized = false;
}
}
/**
* This method traverses all namespaces in the given iterator and calculates
* the coupling metrics for them.
*
* @param ASTArtifactList<ASTNamespace> $namespaces
*
* @return void
*
* @since 0.10.2
*/
private function doAnalyze($namespaces)
{
$this->fireStartAnalyzer();
$this->reset();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->postProcessTemporaryCouplingMap();
$this->fireEndAnalyzer();
}
/**
* This method resets all internal state variables before the analyzer can
* start the object tree traversal.
*
* @return void
*
* @since 0.10.2
*/
private function reset()
{
$this->calls = 0;
$this->fanout = 0;
$this->nodeMetrics = array();
$this->dependencyMap = array();
}
/**
* This method takes the temporary coupling map with node IDs and calculates
* the concrete node metrics.
*
* @return void
*
* @since 0.10.2
*/
private function postProcessTemporaryCouplingMap()
{
foreach ($this->dependencyMap as $id => $metrics) {
$afferentCoupling = count($metrics['ca']);
$efferentCoupling = count($metrics['ce']);
$this->nodeMetrics[$id] = array(
self::M_CA => $afferentCoupling,
self::M_CBO => $efferentCoupling,
self::M_CE => $efferentCoupling
);
$this->fanout += $efferentCoupling;
}
$this->dependencyMap = array();
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
$fanouts = array();
if (($type = $function->getReturnClass()) !== null) {
$fanouts[] = $type;
++$this->fanout;
}
foreach ($function->getExceptionClasses() as $type) {
if (in_array($type, $fanouts, true) === false) {
$fanouts[] = $type;
++$this->fanout;
}
}
foreach ($function->getDependencies() as $type) {
if (in_array($type, $fanouts, true) === false) {
$fanouts[] = $type;
++$this->fanout;
}
}
foreach ($fanouts as $fanout) {
$this->initDependencyMap($fanout);
$this->dependencyMap[$fanout->getId()]['ca'][$function->getId()] = true;
}
$this->countCalls($function);
$this->fireEndFunction($function);
}
/**
* Visit method for classes that will be called by PDepend during the
* analysis phase with the current context class.
*
* @return void
*
* @since 0.10.2
*/
public function visitClass(ASTClass $class)
{
$this->initDependencyMap($class);
parent::visitClass($class);
}
/**
* Visit method for interfaces that will be called by PDepend during the
* analysis phase with the current context interface.
*
* @return void
*
* @since 0.10.2
*/
public function visitInterface(ASTInterface $interface)
{
$this->initDependencyMap($interface);
parent::visitInterface($interface);
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
$declaringClass = $method->getParent();
$this->calculateCoupling(
$declaringClass,
$method->getReturnClass()
);
foreach ($method->getExceptionClasses() as $type) {
$this->calculateCoupling($declaringClass, $type);
}
foreach ($method->getDependencies() as $type) {
$this->calculateCoupling($declaringClass, $type);
}
$this->countCalls($method);
$this->fireEndMethod($method);
}
/**
* Visits a property node.
*
* @return void
*/
public function visitProperty(ASTProperty $property)
{
$this->fireStartProperty($property);
$this->calculateCoupling(
$property->getDeclaringClass(),
$property->getClass()
);
$this->fireEndProperty($property);
}
/**
* Calculates the coupling between the given types.
*
* @param AbstractASTType $coupledType
*
* @return void
*
* @since 0.10.2
*/
private function calculateCoupling(
AbstractASTType $declaringType,
AbstractASTType $coupledType = null
) {
$this->initDependencyMap($declaringType);
if (null === $coupledType) {
return;
}
if ($coupledType->isSubtypeOf($declaringType)
|| $declaringType->isSubtypeOf($coupledType)
) {
return;
}
$this->initDependencyMap($coupledType);
$this->dependencyMap[
$declaringType->getId()
]['ce'][
$coupledType->getId()
] = true;
$this->dependencyMap[
$coupledType->getId()
]['ca'][
$declaringType->getId()
] = true;
}
/**
* This method will initialize a temporary coupling container for the given
* given class or interface instance.
*
* @return void
*
* @since 0.10.2
*/
private function initDependencyMap(AbstractASTType $type)
{
if (isset($this->dependencyMap[$type->getId()])) {
return;
}
$this->dependencyMap[$type->getId()] = array(
'ce' => array(),
'ca' => array()
);
}
/**
* Counts all calls within the given <b>$callable</b>
*
* @return void
*/
private function countCalls(AbstractASTCallable $callable)
{
$invocations = $callable->findChildrenOfType('PDepend\\Source\\AST\\ASTInvocation');
$invoked = array();
foreach ($invocations as $invocation) {
$parents = $invocation->getParentsOfType('PDepend\\Source\\AST\\ASTMemberPrimaryPrefix');
$image = '';
foreach ($parents as $parent) {
$child = $parent->getChild(0);
if ($child !== $invocation) {
$image .= $child->getImage() . '.';
}
}
$image .= $invocation->getImage() . '()';
$invoked[$image] = $image;
}
$this->calls += count($invoked);
}
}
@@ -0,0 +1,269 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AggregateAnalyzer;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Util\Coverage\Factory;
use PDepend\Util\Coverage\Report;
/**
* This analyzer calculates the C.R.A.P. index for methods an functions when a
* clover coverage report was supplied. This report can be supplied by using the
* command line option <b>--coverage-report=</b>.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class CrapIndexAnalyzer extends AbstractAnalyzer implements AggregateAnalyzer, AnalyzerNodeAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_CRAP_INDEX = 'crap',
M_COVERAGE = 'cov';
/**
* The report option name.
*/
const REPORT_OPTION = 'coverage-report';
/**
* Calculated crap metrics.
*
* @var array<string, array<string, float>>
*/
private $metrics = null;
/**
* The coverage report instance representing the supplied coverage report
* file.
*
* @var Report
*/
private $report = null;
/**
* @var CyclomaticComplexityAnalyzer
*/
private $ccnAnalyzer = null;
/**
* Returns <b>true</b> when this analyzer is enabled.
*
* @return bool
*/
public function isEnabled()
{
return isset($this->options[self::REPORT_OPTION]);
}
/**
* Returns the calculated metrics for the given node or an empty <b>array</b>
* when no metrics exist for the given node.
*
* @return array<string, float>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->metrics[$artifact->getId()])) {
return $this->metrics[$artifact->getId()];
}
return array();
}
/**
* Returns an array with analyzer class names that are required by the crap
* index analyzers.
*
* @return array<string>
*/
public function getRequiredAnalyzers()
{
return array('PDepend\\Metrics\\Analyzer\\CyclomaticComplexityAnalyzer');
}
/**
* Adds an analyzer that this analyzer depends on.
*
* @param CyclomaticComplexityAnalyzer $analyzer
*
* @return void
*/
public function addAnalyzer(Analyzer $analyzer)
{
$this->ccnAnalyzer = $analyzer;
}
/**
* Performs the crap index analysis.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->isEnabled() && $this->metrics === null) {
$this->doAnalyze($namespaces);
}
}
/**
* Performs the crap index analysis.
*
* @param ASTArtifactList<ASTNamespace> $namespaces
*
* @return void
*/
private function doAnalyze($namespaces)
{
$this->metrics = array();
$this->ccnAnalyzer->analyze($namespaces);
$this->fireStartAnalyzer();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
}
/**
* Visits the given method.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
if ($method->isAbstract() === false) {
$this->visitCallable($method);
}
}
/**
* Visits the given function.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->visitCallable($function);
}
/**
* Visits the given callable instance.
*
* @return void
*/
private function visitCallable(AbstractASTCallable $callable)
{
$this->metrics[$callable->getId()] = array(
self::M_CRAP_INDEX => $this->calculateCrapIndex($callable),
self::M_COVERAGE => $this->calculateCoverage($callable)
);
}
/**
* Calculates the crap index for the given callable.
*
* @return float
*/
private function calculateCrapIndex(AbstractASTCallable $callable)
{
$report = $this->createOrReturnCoverageReport();
$complexity = $this->ccnAnalyzer->getCcn2($callable);
$coverage = $report->getCoverage($callable);
if ($coverage == 0) {
return pow($complexity, 2) + $complexity;
} elseif ($coverage > 99.5) {
return $complexity;
}
return pow($complexity, 2) * pow(1 - $coverage / 100, 3) + $complexity;
}
/**
* Calculates the code coverage for the given callable object.
*
* @return float
*/
private function calculateCoverage(AbstractASTCallable $callable)
{
return $this->createOrReturnCoverageReport()->getCoverage($callable);
}
/**
* Returns a previously created report instance or creates a new report
* instance.
*
* @return Report
*/
private function createOrReturnCoverageReport()
{
if ($this->report === null) {
$this->report = $this->createCoverageReport();
}
return $this->report;
}
/**
* Creates a new coverage report instance.
*
* @return Report
*/
private function createCoverageReport()
{
$factory = new Factory();
return $factory->create($this->options['coverage-report']);
}
}
@@ -0,0 +1,473 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTNode;
use PDepend\Source\AST\ASTSwitchLabel;
/**
* This class calculates the Cyclomatic Complexity Number(CCN) for the project,
* methods and functions.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class CyclomaticComplexityAnalyzer extends AbstractCachingAnalyzer implements AnalyzerNodeAware, AnalyzerProjectAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_CYCLOMATIC_COMPLEXITY_1 = 'ccn',
M_CYCLOMATIC_COMPLEXITY_2 = 'ccn2';
/**
* The project Cyclomatic Complexity Number.
*
* @var int
*/
private $ccn = 0;
/**
* Extended Cyclomatic Complexity Number(CCN2) for the project.
*
* @var int
*/
private $ccn2 = 0;
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->metrics === null) {
$this->loadCache();
$this->fireStartAnalyzer();
// Init node metrics
$this->metrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
$this->unloadCache();
}
}
/**
* Returns the cyclomatic complexity for the given <b>$node</b> instance.
*
* @return int
*/
public function getCcn(ASTArtifact $node)
{
$metrics = $this->getNodeMetrics($node);
if (isset($metrics[self::M_CYCLOMATIC_COMPLEXITY_1])) {
return $metrics[self::M_CYCLOMATIC_COMPLEXITY_1];
}
return 0;
}
/**
* Returns the extended cyclomatic complexity for the given <b>$node</b>
* instance.
*
* @return int
*/
public function getCcn2(ASTArtifact $node)
{
$metrics = $this->getNodeMetrics($node);
if (isset($metrics[self::M_CYCLOMATIC_COMPLEXITY_2])) {
return $metrics[self::M_CYCLOMATIC_COMPLEXITY_2];
}
return 0;
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b>. If there are no metrics for the requested
* node, this method will return an empty <b>array</b>.
*
* @return array<string, integer>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->metrics[$artifact->getId()])) {
return $this->metrics[$artifact->getId()];
}
return array();
}
/**
* Provides the project summary metrics as an <b>array</b>.
*
* @return array<string, integer>
*/
public function getProjectMetrics()
{
return array(
self::M_CYCLOMATIC_COMPLEXITY_1 => $this->ccn,
self::M_CYCLOMATIC_COMPLEXITY_2 => $this->ccn2
);
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
if (false === $this->restoreFromCache($function)) {
$this->calculateComplexity($function);
}
$this->updateProjectMetrics($function->getId());
$this->fireEndFunction($function);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
// Empty visit method, we don't want interface metrics
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
if (false === $this->restoreFromCache($method)) {
$this->calculateComplexity($method);
}
$this->updateProjectMetrics($method->getId());
$this->fireEndMethod($method);
}
/**
* Visits methods, functions or closures and calculated their complexity.
*
* @return void
*
* @since 0.9.8
*/
public function calculateComplexity(AbstractASTCallable $callable)
{
$data = array(
self::M_CYCLOMATIC_COMPLEXITY_1 => 1,
self::M_CYCLOMATIC_COMPLEXITY_2 => 1
);
foreach ($callable->getChildren() as $child) {
$data = $child->accept($this, $data);
}
$this->metrics[$callable->getId()] = $data;
}
/**
* Stores the complexity of a node and updates the corresponding project
* values.
*
* @param string $nodeId Identifier of the analyzed item.
*
* @return void
*
* @since 1.0.0
*/
private function updateProjectMetrics($nodeId)
{
$this->ccn += $this->metrics[$nodeId][self::M_CYCLOMATIC_COMPLEXITY_1];
$this->ccn2 += $this->metrics[$nodeId][self::M_CYCLOMATIC_COMPLEXITY_2];
}
/**
* Visits a boolean AND-expression.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitBooleanAndExpression($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a boolean OR-expression.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitBooleanOrExpression($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a switch label.
*
* @param ASTSwitchLabel $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitSwitchLabel($node, $data)
{
if (!$node->isDefault()) {
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
}
return $this->visit($node, $data);
}
/**
* Visits a catch statement.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitCatchStatement($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits an elseif statement.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitElseIfStatement($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a for statement.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitForStatement($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a foreach statement.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitForeachStatement($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits an if statement.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitIfStatement($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a logical AND expression.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitLogicalAndExpression($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a logical OR expression.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitLogicalOrExpression($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a ternary operator.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitConditionalExpression($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a while-statement.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.8
*/
public function visitWhileStatement($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
/**
* Visits a do/while-statement.
*
* @param ASTNode $node The currently visited node.
* @param array<string, integer> $data The previously calculated ccn values.
*
* @return array<string, integer>
*
* @since 0.9.12
*/
public function visitDoWhileStatement($node, $data)
{
++$data[self::M_CYCLOMATIC_COMPLEXITY_1];
++$data[self::M_CYCLOMATIC_COMPLEXITY_2];
return $this->visit($node, $data);
}
}
@@ -0,0 +1,483 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
/**
* This visitor generates the metrics for the analyzed namespaces.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class DependencyAnalyzer extends AbstractAnalyzer
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_NUMBER_OF_CLASSES = 'tc',
M_NUMBER_OF_CONCRETE_CLASSES = 'cc',
M_NUMBER_OF_ABSTRACT_CLASSES = 'ac',
M_AFFERENT_COUPLING = 'ca',
M_EFFERENT_COUPLING = 'ce',
M_ABSTRACTION = 'a',
M_INSTABILITY = 'i',
M_DISTANCE = 'd';
/**
* Hash with all calculated node metrics.
*
* <code>
* array(
* '0375e305-885a-4e91-8b5c-e25bda005438' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* ),
* 'e60c22f0-1a63-4c40-893e-ed3b35b84d0b' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* )
* )
* </code>
*
* @var array<string, array<string, mixed>>
*/
private $nodeMetrics = null;
/**
* @var array<string, ASTNamespace>
*/
protected $nodeSet = array();
/**
* Nodes in which the current analyzed dependency is used.
*
* @var array<string, array<int, ASTNamespace>>
*/
private $efferentNodes = array();
/**
* Nodes that is used by the current analyzed node.
*
* @var array<string, array<int, ASTNamespace>>
*/
private $afferentNodes = array();
/**
* All collected cycles for the input code.
*
* <code>
* array(
* <namespace-id> => array(
* ASTNamespace {},
* ASTNamespace {},
* ),
* <namespace-id> => array(
* ASTNamespace {},
* ASTNamespace {},
* ),
* )
* </code>
*
* @var array<string, array<int, AbstractASTArtifact>|null>
*/
private $collectedCycles = array();
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->nodeMetrics === null) {
$this->fireStartAnalyzer();
$this->nodeMetrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->postProcess();
$this->calculateAbstractness();
$this->calculateInstability();
$this->calculateDistance();
$this->fireEndAnalyzer();
}
}
/**
* Returns the statistics for the requested node.
*
* @return array<string, mixed>
*/
public function getStats(AbstractASTArtifact $node)
{
$stats = array();
if (isset($this->nodeMetrics[$node->getId()])) {
$stats = $this->nodeMetrics[$node->getId()];
}
return $stats;
}
/**
* Returns an array of all afferent nodes.
*
* @return AbstractASTArtifact[]
*/
public function getAfferents(AbstractASTArtifact $node)
{
$afferents = array();
if (isset($this->afferentNodes[$node->getId()])) {
$afferents = $this->afferentNodes[$node->getId()];
}
ksort($afferents);
return $afferents;
}
/**
* Returns an array of all efferent nodes.
*
* @return ASTNamespace[]
*/
public function getEfferents(AbstractASTArtifact $node)
{
$efferents = array();
if (isset($this->efferentNodes[$node->getId()])) {
$efferents = $this->efferentNodes[$node->getId()];
}
ksort($efferents);
return $efferents;
}
/**
* Returns an array of nodes that build a cycle for the requested node or it
* returns <b>null</b> if no cycle exists .
*
* @param ASTNamespace $node
*
* @return AbstractASTArtifact[]
*/
public function getCycle(AbstractASTArtifact $node)
{
if (array_key_exists($node->getId(), $this->collectedCycles)) {
return $this->collectedCycles[$node->getId()];
}
$list = array();
if ($this->collectCycle($list, $node)) {
$this->collectedCycles[$node->getId()] = $list;
} else {
$this->collectedCycles[$node->getId()] = null;
}
return $this->collectedCycles[$node->getId()];
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
$namespace = $method->getParent()->getNamespace();
foreach ($method->getDependencies() as $dependency) {
$this->collectDependencies($namespace, $dependency->getNamespace());
}
$this->fireEndMethod($method);
}
/**
* Visits a namespace node.
*
* @return void
*/
public function visitNamespace(ASTNamespace $namespace)
{
$this->fireStartNamespace($namespace);
$this->initNamespaceMetric($namespace);
$this->nodeSet[$namespace->getId()] = $namespace;
foreach ($namespace->getTypes() as $type) {
$type->accept($this);
}
$this->fireEndNamespace($namespace);
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
$this->fireStartClass($class);
$this->visitType($class);
$this->fireEndClass($class);
}
/**
* Visits an interface node.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
$this->fireStartInterface($interface);
$this->visitType($interface);
$this->fireEndInterface($interface);
}
/**
* Generic visit method for classes and interfaces. Both visit methods
* delegate calls to this method.
*
* @return void
*/
protected function visitType(AbstractASTClassOrInterface $type)
{
$id = $type->getNamespace()->getId();
// Increment total classes count
++$this->nodeMetrics[$id][self::M_NUMBER_OF_CLASSES];
// Check for abstract or concrete class
if ($type->isAbstract()) {
++$this->nodeMetrics[$id][self::M_NUMBER_OF_ABSTRACT_CLASSES];
} else {
++$this->nodeMetrics[$id][self::M_NUMBER_OF_CONCRETE_CLASSES];
}
foreach ($type->getDependencies() as $dependency) {
$this->collectDependencies(
$type->getNamespace(),
$dependency->getNamespace()
);
}
foreach ($type->getMethods() as $method) {
$method->accept($this);
}
}
/**
* Collects the dependencies between the two given namespaces.
*
* @return void
*/
private function collectDependencies(ASTNamespace $namespaceA, ASTNamespace $namespaceB)
{
$idA = $namespaceA->getId();
$idB = $namespaceB->getId();
if ($idB === $idA) {
return;
}
// Create a container for this dependency
$this->initNamespaceMetric($namespaceB);
if (!in_array($idB, $this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING])) {
$this->nodeMetrics[$idA][self::M_EFFERENT_COUPLING][] = $idB;
$this->nodeMetrics[$idB][self::M_AFFERENT_COUPLING][] = $idA;
}
}
/**
* Initializes the node metric record for the given <b>$namespace</b>.
*
* @return void
*/
protected function initNamespaceMetric(ASTNamespace $namespace)
{
$id = $namespace->getId();
if (!isset($this->nodeMetrics[$id])) {
$this->nodeSet[$id] = $namespace;
$this->nodeMetrics[$id] = array(
self::M_NUMBER_OF_CLASSES => 0,
self::M_NUMBER_OF_CONCRETE_CLASSES => 0,
self::M_NUMBER_OF_ABSTRACT_CLASSES => 0,
self::M_AFFERENT_COUPLING => array(),
self::M_EFFERENT_COUPLING => array(),
self::M_ABSTRACTION => 0,
self::M_INSTABILITY => 0,
self::M_DISTANCE => 0
);
}
}
/**
* Post processes all analyzed nodes.
*
* @return void
*/
protected function postProcess()
{
foreach ($this->nodeMetrics as $id => $metrics) {
$this->afferentNodes[$id] = array();
foreach ($metrics[self::M_AFFERENT_COUPLING] as $caId) {
$this->afferentNodes[$id][] = $this->nodeSet[$caId];
}
sort($this->afferentNodes[$id]);
$this->efferentNodes[$id] = array();
foreach ($metrics[self::M_EFFERENT_COUPLING] as $ceId) {
$this->efferentNodes[$id][] = $this->nodeSet[$ceId];
}
sort($this->efferentNodes[$id]);
$afferent = count($metrics[self::M_AFFERENT_COUPLING]);
$efferent = count($metrics[self::M_EFFERENT_COUPLING]);
$this->nodeMetrics[$id][self::M_AFFERENT_COUPLING] = $afferent;
$this->nodeMetrics[$id][self::M_EFFERENT_COUPLING] = $efferent;
}
}
/**
* Calculates the abstractness for all analyzed nodes.
*
* @return void
*/
protected function calculateAbstractness()
{
foreach ($this->nodeMetrics as $id => $metrics) {
if ($metrics[self::M_NUMBER_OF_CLASSES] !== 0) {
$this->nodeMetrics[$id][self::M_ABSTRACTION] = (
$metrics[self::M_NUMBER_OF_ABSTRACT_CLASSES] /
$metrics[self::M_NUMBER_OF_CLASSES]
);
}
}
}
/**
* Calculates the instability for all analyzed nodes.
*
* @return void
*/
protected function calculateInstability()
{
foreach ($this->nodeMetrics as $id => $metrics) {
// Count total incoming and outgoing dependencies
$total = (
$metrics[self::M_AFFERENT_COUPLING] +
$metrics[self::M_EFFERENT_COUPLING]
);
if ($total !== 0) {
$this->nodeMetrics[$id][self::M_INSTABILITY] = (
$metrics[self::M_EFFERENT_COUPLING] / $total
);
}
}
}
/**
* Calculates the distance to an optimal value.
*
* @return void
*/
protected function calculateDistance()
{
foreach ($this->nodeMetrics as $id => $metrics) {
$this->nodeMetrics[$id][self::M_DISTANCE] = abs(
($metrics[self::M_ABSTRACTION] + $metrics[self::M_INSTABILITY]) - 1
);
}
}
/**
* Collects a single cycle that is reachable by this namespace. All namespaces
* that are part of the cylce are stored in the given <b>$list</b> array.
*
* @param ASTNamespace[] $list
*
* @return bool If this method detects a cycle the return value is <b>true</b>
* otherwise this method will return <b>false</b>.
*/
protected function collectCycle(array &$list, ASTNamespace $namespace)
{
if (in_array($namespace, $list, true)) {
$list[] = $namespace;
return true;
}
$list[] = $namespace;
foreach ($this->getEfferents($namespace) as $efferent) {
if ($this->collectCycle($list, $efferent)) {
return true;
}
}
if (is_int($idx = array_search($namespace, $list, true))) {
unset($list[$idx]);
}
return false;
}
}
@@ -0,0 +1,397 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2015, Matthias Mullie <pdepend@mullie.eu>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2015 Matthias Mullie. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\Tokenizer\Tokens;
/**
* This class calculates the Halstead Complexity Measures for the project,
* methods and functions.
*
* @copyright 2015 Matthias Mullie. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class HalsteadAnalyzer extends AbstractCachingAnalyzer implements AnalyzerNodeAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_HALSTEAD_LENGTH = 'hnt', // N = N1 + N2 (total operators + operands)
M_HALSTEAD_VOCABULARY = 'hnd', // n = n1 + n2 (distinct operators + operands)
M_HALSTEAD_VOLUME = 'hv', // V = N * log2(n)
M_HALSTEAD_DIFFICULTY = 'hd', // D = (n1 / 2) * (N2 / n2)
M_HALSTEAD_LEVEL = 'hl', // L = 1 / D
M_HALSTEAD_EFFORT = 'he', // E = V * D
M_HALSTEAD_TIME = 'ht', // T = E / 18
M_HALSTEAD_BUGS = 'hb', // B = (E ** (2/3)) / 3000
M_HALSTEAD_CONTENT = 'hi'; // I = (V / D)
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->metrics === null) {
$this->loadCache();
$this->fireStartAnalyzer();
// Init node metrics
$this->metrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
$this->unloadCache();
}
}
/**
* This method will return an <b>array</b> with all generated basis metrics
* for the given <b>$node</b> (n1, n2, N1, N2). If there are no metrics for
* the requested node, this method will return an empty <b>array</b>.
*
* @return array<string, integer>
*/
public function getNodeBasisMetrics(ASTArtifact $artifact)
{
if (isset($this->metrics[$artifact->getId()])) {
return $this->metrics[$artifact->getId()];
}
return array();
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b>. If there are no metrics for the requested
* node, this method will return an empty <b>array</b>.
*
* @return array<string, float>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
$basis = $this->getNodeBasisMetrics($artifact);
if ($basis) {
return $this->calculateHalsteadMeasures($basis);
}
return array();
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
if (false === $this->restoreFromCache($function)) {
$this->calculateHalsteadBasis($function);
}
$this->fireEndFunction($function);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
// Empty visit method, we don't want interface metrics
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
if (false === $this->restoreFromCache($method)) {
$this->calculateHalsteadBasis($method);
}
$this->fireEndMethod($method);
}
/**
* @see http://www.scribd.com/doc/99533/Halstead-s-Operators-and-Operands-in-C-C-JAVA-by-Indranil-Nandy
*
* @return void
*/
public function calculateHalsteadBasis(AbstractASTCallable $callable)
{
$operators = array();
$operands = array();
$skipUntil = null;
$tokens = $callable->getTokens();
foreach ($tokens as $i => $token) {
/*
* Some operations should be ignored, e.g. function declarations.
* When we encounter a new function, we'll skip all tokens until we
* find the closing token.
*/
if ($skipUntil !== null) {
if ($token->type === $skipUntil) {
$skipUntil = null;
}
continue;
}
switch ($token->type) {
// A pair of parenthesis is considered a single operator.
case Tokens::T_PARENTHESIS_CLOSE:
case Tokens::T_CURLY_BRACE_CLOSE:
case Tokens::T_SQUARED_BRACKET_CLOSE:
case Tokens::T_ANGLE_BRACKET_CLOSE:
break;
// A label is considered an operator if it is used as the target
// of a GOTO statement.
case Tokens::T_GOTO:
$operators[] = $token->image;
// Ignore next token as operand but count as operator instead.
$skipUntil = $tokens[$i + 1]->type;
$operators[] = $tokens[$i + 1]->image;
break;
/*
* The following control structures case ...: for (...) if (...)
* switch (...) while(...) and try-catch (...) are treated in a
* special way. The colon and the parentheses are considered to
* be a part of the constructs. The case and the colon or the
* “for (...)”, “if (...)”, “switch (...)”, “while(...)”,
* “try-catch( )” are counted together as one operator.
*/
// case Tokens::T_SWITCH: // not followed by ()
// case Tokens::T_TRY: // not followed by ()
// case Tokens::T_DO: // always comes with while, which accounts for () already
case Tokens::T_IF:
case Tokens::T_FOR:
case Tokens::T_FOREACH:
case Tokens::T_WHILE:
case Tokens::T_CATCH:
$operators[] = $token->image;
/*
* These are always followed by parenthesis, which would add
* another operator (only opening parenthesis counts)
* so we'll have to skip that one.
*/
$skipUntil = Tokens::T_PARENTHESIS_OPEN;
break;
/*
* The ternary operator ‘?’ followed by ‘:’ is considered a
* single operator as it is equivalent to “if-else” construct.
*/
case Tokens::T_COLON:
/*
* Colon is used after keyword, where it counts as part of
* that operator, or in ternary operator, where it also
* counts as 1.
*/
break;
// The comments are considered neither an operator nor an operand.
case Tokens::T_DOC_COMMENT:
case Tokens::T_COMMENT:
break;
/*
* `new` is considered same as the function call, mainly because
* it's equivalent to the function call.
*/
case Tokens::T_NEW:
break;
/*
* Like T_IF & co, array(..) needs 3 tokens ("array", "(" and
* ")") for what's essentially just 1 operator.
*/
case Tokens::T_ARRAY:
break;
/*
* Class::method or $object->method both only count as 1
* identifier, even though they consist of 3 tokens.
*/
case Tokens::T_NULLSAFE_OBJECT_OPERATOR:
case Tokens::T_OBJECT_OPERATOR:
case Tokens::T_DOUBLE_COLON:
// Glue ->/:: and before & after parts together.
$image = array_pop($operands).$token->image.$tokens[$i + 1]->image;
$operands[] = $image;
// Skip next part (would be seen as operand)
$skipUntil = $tokens[$i + 1]->type;
break;
// Ignore HEREDOC delimiters.
case Tokens::T_START_HEREDOC:
case Tokens::T_END_HEREDOC:
break;
// Ignore PHP open & close tags and non-PHP content.
case Tokens::T_OPEN_TAG:
case Tokens::T_CLOSE_TAG:
case Tokens::T_NO_PHP:
break;
/*
* The function name is considered a single operator when it
* appears as calling a function, but when it appears in
* declarations or in function definitions it is not counted as
* operator.
* Default parameter assignments are not counted.
*/
case Tokens::T_FUNCTION:
// Because `)` could appear in default argument assignment
// (`$var = array()`), we need to skip until `{`, but that
// one should be included in operators.
$skipUntil = Tokens::T_CURLY_BRACE_OPEN;
$operators[] = '{';
break;
/*
* When variables or constants appear in declaration they are
* not considered as operands, they are considered operands only
* when they appear with operators in expressions.
*/
case Tokens::T_VAR:
case Tokens::T_CONST:
$skipUntil = Tokens::T_SEMICOLON;
break;
case Tokens::T_STRING:
// `define` is T_STRING, just like any other identifier.
if ($token->image === 'define') {
// Undo all of "define", "(", name, ",", value, ")"
$skipUntil = Tokens::T_PARENTHESIS_CLOSE;
} else {
$operands[] = $token->image;
}
break;
// Operands
case Tokens::T_CONSTANT_ENCAPSED_STRING:
case Tokens::T_VARIABLE:
case Tokens::T_LNUMBER:
case Tokens::T_DNUMBER:
case Tokens::T_NUM_STRING:
case Tokens::T_NULL:
case Tokens::T_TRUE:
case Tokens::T_FALSE:
case Tokens::T_CLASS_FQN:
case Tokens::T_LINE:
case Tokens::T_METHOD_C:
case Tokens::T_NS_C:
case Tokens::T_DIR:
case TOKENS::T_ENCAPSED_AND_WHITESPACE: // content of HEREDOC
$operands[] = $token->image;
break;
// Everything else is an operator.
default:
$operators[] = $token->image;
break;
}
}
$this->metrics[$callable->getId()] = array(
'n1' => count(array_unique($operators)),
'n2' => count(array_unique($operands)),
'N1' => count($operators),
'N2' => count($operands),
);
}
/**
* Calculates Halstead measures from n1, n2, N1 & N2.
*
* @see http://www.verifysoft.com/en_halstead_metrics.html
* @see http://www.grammatech.com/codesonar/workflow-features/halstead
*
* @param array<string, int> $basis [n1, n2, N1, N2]
*
* @return array<string, float>
*/
public function calculateHalsteadMeasures(array $basis)
{
$measures = array();
$measures[self::M_HALSTEAD_LENGTH] = $basis['N1'] + $basis['N2'];
$measures[self::M_HALSTEAD_VOCABULARY] = $basis['n1'] + $basis['n2'];
$measures[self::M_HALSTEAD_VOLUME] =
$measures[self::M_HALSTEAD_LENGTH] * log($measures[self::M_HALSTEAD_VOCABULARY], 2);
$measures[self::M_HALSTEAD_DIFFICULTY] = ($basis['n1'] / 2) * ($basis['N1'] / ($basis['n2'] ?: 1));
$measures[self::M_HALSTEAD_LEVEL] = 1 / ($measures[self::M_HALSTEAD_DIFFICULTY] ?: 1);
$measures[self::M_HALSTEAD_EFFORT] =
$measures[self::M_HALSTEAD_VOLUME] * $measures[self::M_HALSTEAD_DIFFICULTY];
$measures[self::M_HALSTEAD_TIME] = $measures[self::M_HALSTEAD_EFFORT] / 18;
$measures[self::M_HALSTEAD_BUGS] = pow($measures[self::M_HALSTEAD_EFFORT], (2/3)) / 3000;
$measures[self::M_HALSTEAD_CONTENT] =
$measures[self::M_HALSTEAD_VOLUME] / ($measures[self::M_HALSTEAD_DIFFICULTY] ?: 1);
return $measures;
}
}
@@ -0,0 +1,309 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
/**
* This analyzer calculates class/namespace hierarchy metrics.
*
* This analyzer expects that a node list filter is set, before it starts the
* analyze process. This filter will suppress PHP internal and external library
* stuff.
*
* This analyzer is based on the following metric set:
* - http://www.aivosto.com/project/help/pm-oo-misc.html
*
* This analyzer is based on the following metric set:
* - http://www.aivosto.com/project/help/pm-oo-misc.html
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class HierarchyAnalyzer extends AbstractAnalyzer implements AnalyzerFilterAware, AnalyzerNodeAware, AnalyzerProjectAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_NUMBER_OF_ABSTRACT_CLASSES = 'clsa',
M_NUMBER_OF_CONCRETE_CLASSES = 'clsc',
M_NUMBER_OF_ROOT_CLASSES = 'roots',
M_NUMBER_OF_LEAF_CLASSES = 'leafs';
/**
* Number of all analyzed functions.
*
* @var int
*/
private $fcs = 0;
/**
* Number of all analyzer methods.
*
* @var int
*/
private $mts = 0;
/**
* Number of all analyzed classes.
*
* @var int
*/
private $cls = 0;
/**
* Number of all analyzed abstract classes.
*
* @var int
*/
private $clsa = 0;
/**
* Number of all analyzed interfaces.
*
* @var int
*/
private $interfs = 0;
/**
* Number of all root classes within the analyzed source code.
*
* @var array<string, boolean>
*/
private $roots = array();
/**
* Number of all none leaf classes within the analyzed source code
*
* @var array<string, boolean>
*/
private $noneLeafs = array();
/**
* Hash with all calculated node metrics.
*
* <code>
* array(
* '0375e305-885a-4e91-8b5c-e25bda005438' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* ),
* 'e60c22f0-1a63-4c40-893e-ed3b35b84d0b' => array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* )
* )
* </code>
*
* @var array<string, array<string, int>>
*/
private $nodeMetrics = null;
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->nodeMetrics === null) {
$this->fireStartAnalyzer();
// Init node metrics
$this->nodeMetrics = array();
// Visit all nodes
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
}
}
/**
* Provides the project summary metrics as an <b>array</b>.
*
* @return array<string, mixed>
*/
public function getProjectMetrics()
{
// Count none leaf classes
$noneLeafs = count($this->noneLeafs);
return array(
self::M_NUMBER_OF_ABSTRACT_CLASSES => $this->clsa,
self::M_NUMBER_OF_CONCRETE_CLASSES => $this->cls - $this->clsa,
self::M_NUMBER_OF_ROOT_CLASSES => count($this->roots),
self::M_NUMBER_OF_LEAF_CLASSES => $this->cls - $noneLeafs,
);
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b> instance. If there are no metrics for the
* requested node, this method will return an empty <b>array</b>.
*
* @return array<string, mixed>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->nodeMetrics[$artifact->getId()])) {
return $this->nodeMetrics[$artifact->getId()];
}
return array();
}
/**
* Calculates metrics for the given <b>$class</b> instance.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
if (false === $class->isUserDefined()) {
return;
}
$this->fireStartClass($class);
++$this->cls;
if ($class->isAbstract()) {
++$this->clsa;
}
$parentClass = $class->getParentClass();
if ($parentClass !== null) {
if ($parentClass->getParentClass() === null) {
$this->roots[$parentClass->getId()] = true;
}
$this->noneLeafs[$parentClass->getId()] = true;
}
// Store node metric
$this->nodeMetrics[$class->getId()] = array();
foreach ($class->getMethods() as $method) {
$method->accept($this);
}
foreach ($class->getProperties() as $property) {
$property->accept($this);
}
$this->fireEndClass($class);
}
/**
* Calculates metrics for the given <b>$function</b> instance.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
++$this->fcs;
$this->fireEndFunction($function);
}
/**
* Calculates metrics for the given <b>$interface</b> instance.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
$this->fireStartInterface($interface);
++$this->interfs;
foreach ($interface->getMethods() as $method) {
$method->accept($this);
}
$this->fireEndInterface($interface);
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
++$this->mts;
$this->fireEndMethod($method);
}
/**
* Calculates metrics for the given <b>$namespace</b> instance.
*
* @return void
*/
public function visitNamespace(ASTNamespace $namespace)
{
$this->fireStartNamespace($namespace);
foreach ($namespace->getTypes() as $type) {
$type->accept($this);
}
foreach ($namespace->getFunctions() as $function) {
$function->accept($this);
}
$this->fireEndNamespace($namespace);
}
}
@@ -0,0 +1,362 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTNamespace;
/**
* This analyzer provides two project related inheritance metrics.
*
* <b>ANDC - Average Number of Derived Classes</b>: The average number of direct
* subclasses of a class. This metric only covers classes in the analyzed system,
* no library or environment classes are covered.
*
* <b>AHH - Average Hierarchy Height</b>: The computed average of all inheritance
* trees within the analyzed system, external classes or interfaces are ignored.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class InheritanceAnalyzer extends AbstractAnalyzer implements
AnalyzerNodeAware,
AnalyzerFilterAware,
AnalyzerProjectAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_AVERAGE_NUMBER_DERIVED_CLASSES = 'andc',
M_AVERAGE_HIERARCHY_HEIGHT = 'ahh',
M_DEPTH_OF_INHERITANCE_TREE = 'dit',
M_NUMBER_OF_ADDED_METHODS = 'noam',
M_NUMBER_OF_OVERWRITTEN_METHODS = 'noom',
M_NUMBER_OF_DERIVED_CLASSES = 'nocc',
M_MAXIMUM_INHERITANCE_DEPTH = 'maxDIT';
/**
* Contains the max inheritance depth for all root classes within the
* analyzed system. The array size is equal to the number of analyzed root
* classes.
*
* @var array<integer>
*/
private $rootClasses = array();
/**
* @var array<integer>
*
* @deprecated 3.0.0 This property will no longer be accessible on the public access level in next major version.
*/
public $derivedClasses = array();
/**
* The maximum depth of inheritance tree value within the analyzed source code.
*
* @var int
*/
private $maxDIT = 0;
/**
* The average number of derived classes.
*
* @var float
*/
private $andc = 0;
/**
* The average hierarchy height.
*
* @var float
*/
private $ahh = 0;
/**
* Total number of classes.
*
* @var int
*/
private $numberOfClasses = 0;
/**
* Total number of derived classes.
*
* @var int
*/
private $numberOfDerivedClasses = 0;
/**
* Metrics calculated for a single source node.
*
* @var array<string, array<string, mixed>>
*/
private $nodeMetrics = null;
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b>. If there are no metrics for the requested
* node, this method will return an empty <b>array</b>.
*
* @return array<string, mixed>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->nodeMetrics[$artifact->getId()])) {
return $this->nodeMetrics[$artifact->getId()];
}
return array();
}
/**
* Provides the project summary as an <b>array</b>.
*
* <code>
* array(
* 'andc' => 0.73,
* 'ahh' => 0.56
* )
* </code>
*
* @return array<string, mixed>
*/
public function getProjectMetrics()
{
return array(
self::M_AVERAGE_NUMBER_DERIVED_CLASSES => $this->andc,
self::M_AVERAGE_HIERARCHY_HEIGHT => $this->ahh,
self::M_MAXIMUM_INHERITANCE_DEPTH => $this->maxDIT,
);
}
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->nodeMetrics === null) {
$this->nodeMetrics = array();
$this->fireStartAnalyzer();
$this->doAnalyze($namespaces);
$this->fireEndAnalyzer();
}
}
/**
* Calculates several inheritance related metrics for the given source
* namespaces.
*
* @param ASTArtifactList<ASTNamespace> $namespaces
*
* @return void
*
* @since 0.9.10
*/
private function doAnalyze($namespaces)
{
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
if ($this->numberOfClasses > 0) {
$this->andc = $this->numberOfDerivedClasses / $this->numberOfClasses;
}
if (($count = count($this->rootClasses)) > 0) {
$this->ahh = array_sum($this->rootClasses) / $count;
}
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
if (!$class->isUserDefined()) {
return;
}
$this->fireStartClass($class);
$this->initNodeMetricsForClass($class);
$this->calculateNumberOfDerivedClasses($class);
$this->calculateNumberOfAddedAndOverwrittenMethods($class);
$this->calculateDepthOfInheritanceTree($class);
$this->fireEndClass($class);
}
/**
* Calculates the number of derived classes.
*
* @return void
*
* @since 0.9.5
*/
private function calculateNumberOfDerivedClasses(ASTClass $class)
{
$id = $class->getId();
if (isset($this->derivedClasses[$id]) === false) {
$this->derivedClasses[$id] = 0;
}
$parentClass = $class->getParentClass();
if ($parentClass !== null && $parentClass->isUserDefined()) {
$id = $parentClass->getId();
++$this->numberOfDerivedClasses;
++$this->nodeMetrics[$id][self::M_NUMBER_OF_DERIVED_CLASSES];
}
}
/**
* Calculates the maximum HIT for the given class.
*
* @return void
*
* @since 0.9.10
*/
private function calculateDepthOfInheritanceTree(ASTClass $class)
{
$dit = 0;
$id = $class->getId();
$root = $class->getId();
foreach ($class->getParentClasses() as $parent) {
if (!$parent->isUserDefined()) {
++$dit;
}
++$dit;
$root = $parent->getId();
}
// Collect max dit value
$this->maxDIT = max($this->maxDIT, $dit);
if (empty($this->rootClasses[$root]) || $this->rootClasses[$root] < $dit) {
$this->rootClasses[$root] = $dit;
}
$this->nodeMetrics[$id][self::M_DEPTH_OF_INHERITANCE_TREE] = $dit;
}
/**
* Calculates two metrics. The number of added methods and the number of
* overwritten methods.
*
* @return void
*
* @since 0.9.10
*/
private function calculateNumberOfAddedAndOverwrittenMethods(ASTClass $class)
{
$parentClass = $class->getParentClass();
if ($parentClass === null) {
return;
}
$parentMethodNames = array();
foreach ($parentClass->getAllMethods() as $method) {
$parentMethodNames[$method->getName()] = $method->isAbstract();
}
$numberOfAddedMethods = 0;
$numberOfOverwrittenMethods = 0;
foreach ($class->getAllMethods() as $method) {
if ($method->getParent() !== $class) {
continue;
}
if (isset($parentMethodNames[$method->getName()])) {
if (!$parentMethodNames[$method->getName()]) {
++$numberOfOverwrittenMethods;
}
} else {
++$numberOfAddedMethods;
}
}
$id = $class->getId();
$this->nodeMetrics[$id][self::M_NUMBER_OF_ADDED_METHODS] = $numberOfAddedMethods;
$this->nodeMetrics[$id][self::M_NUMBER_OF_OVERWRITTEN_METHODS] = $numberOfOverwrittenMethods;
}
/**
* Initializes a empty metric container for the given class node.
*
* @return void
*
* @since 0.9.10
*/
private function initNodeMetricsForClass(ASTClass $class)
{
$id = $class->getId();
if (isset($this->nodeMetrics[$id])) {
return;
}
++$this->numberOfClasses;
$this->nodeMetrics[$id] = array(
self::M_DEPTH_OF_INHERITANCE_TREE => 0,
self::M_NUMBER_OF_ADDED_METHODS => 0,
self::M_NUMBER_OF_DERIVED_CLASSES => 0,
self::M_NUMBER_OF_OVERWRITTEN_METHODS => 0
);
foreach ($class->getParentClasses() as $parent) {
$this->initNodeMetricsForClass($parent);
}
}
}
@@ -0,0 +1,209 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2015, Matthias Mullie <pdepend@mullie.eu>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2015 Matthias Mullie. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
/**
* This class calculates the Halstead Complexity Measures for the project,
* methods and functions.
*
* @copyright 2015 Matthias Mullie. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class MaintainabilityIndexAnalyzer extends AbstractCachingAnalyzer implements AnalyzerNodeAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_MAINTAINABILITY_INDEX = 'mi';
/**
* @var CyclomaticComplexityAnalyzer
*/
private $analyzersCCN;
/**
* @var HalsteadAnalyzer
*/
private $analyzersHalstead;
/**
* @var NodeLocAnalyzer
*/
private $analyzersLOC;
/**
* Maintainability index is a combination of cyclomatic complexity,
* halstead volume & lines of code, all of which we already have analyzers
* for.
*
* @param array<string, mixed> $options
*/
public function __construct(array $options = array())
{
parent::__construct($options);
$this->analyzersCCN = new CyclomaticComplexityAnalyzer();
$this->analyzersHalstead = new HalsteadAnalyzer();
$this->analyzersLOC = new NodeLocAnalyzer();
}
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
$this->analyzersCCN->setCache($this->getCache());
$this->analyzersCCN->analyze($namespaces);
$this->analyzersHalstead->setCache($this->getCache());
$this->analyzersHalstead->analyze($namespaces);
$this->analyzersLOC->setCache($this->getCache());
$this->analyzersLOC->analyze($namespaces);
if ($this->metrics === null) {
$this->loadCache();
$this->fireStartAnalyzer();
// Init node metrics
$this->metrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
$this->unloadCache();
}
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b>. If there are no metrics for the requested
* node, this method will return an empty <b>array</b>.
*
* @return array<string, float>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
if (isset($this->metrics[$artifact->getId()])) {
return $this->metrics[$artifact->getId()];
}
return array();
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
if (false === $this->restoreFromCache($function)) {
$this->calculateMaintainabilityIndex($function);
}
$this->fireEndFunction($function);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
// Empty visit method, we don't want interface metrics
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
if (false === $this->restoreFromCache($method)) {
$this->calculateMaintainabilityIndex($method);
}
$this->fireEndMethod($method);
}
/**
* @see http://blogs.msdn.com/b/codeanalysis/archive/2007/11/20/maintainability-index-range-and-meaning.aspx
*
* @return void
*/
public function calculateMaintainabilityIndex(AbstractASTCallable $callable)
{
$cyclomaticComplexity = $this->analyzersCCN->getCcn2($callable);
$halstead = $this->analyzersHalstead->getNodeMetrics($callable);
$halsteadVolume = $halstead[HalsteadAnalyzer::M_HALSTEAD_VOLUME];
$loc = $this->analyzersLOC->getNodeMetrics($callable);
$eloc = $loc[NodeLocAnalyzer::M_EXECUTABLE_LINES_OF_CODE];
$maintainabilityIndex = 171 - 5.2 * log($halsteadVolume) - 0.23 * $cyclomaticComplexity - 16.2 * log($eloc);
$maintainabilityIndex = min(100, max(0, $maintainabilityIndex * 100 / 171));
$this->metrics[$callable->getId()] = array(self::M_MAINTAINABILITY_INDEX => $maintainabilityIndex);
}
}
@@ -0,0 +1,582 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Source\AST\AbstractASTCallable;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTBooleanAndExpression;
use PDepend\Source\AST\ASTBooleanOrExpression;
use PDepend\Source\AST\ASTConditionalExpression;
use PDepend\Source\AST\ASTElseIfStatement;
use PDepend\Source\AST\ASTExpression;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTIfStatement;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTLogicalAndExpression;
use PDepend\Source\AST\ASTLogicalOrExpression;
use PDepend\Source\AST\ASTLogicalXorExpression;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTNode;
use PDepend\Source\AST\ASTStatement;
use PDepend\Source\AST\ASTSwitchLabel;
use PDepend\Util\MathUtil;
/**
* This analyzer calculates the NPath complexity of functions and methods. The
* NPath complexity metric measures the acyclic execution paths through a method
* or function. See Nejmeh, Communications of the ACM Feb 1988 pp 188-200.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class NPathComplexityAnalyzer extends AbstractCachingAnalyzer implements AnalyzerFilterAware, AnalyzerNodeAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_NPATH_COMPLEXITY = 'npath';
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->metrics === null) {
$this->loadCache();
$this->fireStartAnalyzer();
$this->metrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
$this->unloadCache();
}
}
/**
* This method will return an <b>array</b> with all generated metric values
* for the node with the given <b>$id</b> identifier. If there are no
* metrics for the requested node, this method will return an empty <b>array</b>.
*
* <code>
* array(
* 'npath' => '17'
* )
* </code>
*
* @return array<string, string>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
$metric = array();
if (isset($this->metrics[$artifact->getId()])) {
$metric = array(self::M_NPATH_COMPLEXITY => $this->metrics[$artifact->getId()]);
}
return $metric;
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
// Empty visit method, we don't want interface metrics
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
if (false === $this->restoreFromCache($function)) {
$this->calculateComplexity($function);
}
$this->fireEndFunction($function);
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
if (false === $this->restoreFromCache($method)) {
$this->calculateComplexity($method);
}
$this->fireEndMethod($method);
}
/**
* This method will calculate the NPath complexity for the given callable
* instance.
*
* @return void
*
* @since 0.9.12
*/
protected function calculateComplexity(AbstractASTCallable $callable)
{
$npath = '1';
foreach ($callable->getChildren() as $child) {
$stmt = $child->accept($this, $npath);
$npath = MathUtil::mul($npath, $stmt);
}
$this->metrics[$callable->getId()] = $npath;
}
/**
* This method calculates the NPath Complexity of a conditional-statement,
* the meassured value is then returned as a string.
*
* <code>
* <expr1> ? <expr2> : <expr3>
*
* -- NP(?) = NP(<expr1>) + NP(<expr2>) + NP(<expr3>) + 2 --
* </code>
*
* @param ASTNode $node
* @param numeric-string $data
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitConditionalExpression($node, $data)
{
// Calculate the complexity of the condition
$parent = $node->getParent()->getChild(0);
$npath = $this->sumComplexity($parent);
// New PHP 5.3 ifsetor-operator $x ?: $y
if (count($node->getChildren()) === 1) {
$npath = MathUtil::mul($npath, '2');
}
// The complexity of each child has no minimum
foreach ($node->getChildren() as $child) {
$cn = $this->sumComplexity($child);
$npath = MathUtil::add($npath, $cn);
}
// Add 2 for the branching per the NPath spec
$npath = MathUtil::add($npath, '2');
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of a do-while-statement, the
* meassured value is then returned as a string.
*
* <code>
* do
* <do-range>
* while (<expr>)
* S;
*
* -- NP(do) = NP(<do-range>) + NP(<expr>) + 1 --
* </code>
*
* @param ASTNode $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitDoWhileStatement($node, $data)
{
$stmt = $node->getChild(0)->accept($this, '1');
$expr = $this->sumComplexity($node->getChild(1));
$npath = MathUtil::add($expr, $stmt);
$npath = MathUtil::add($npath, '1');
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of an elseif-statement, the
* meassured value is then returned as a string.
*
* <code>
* elseif (<expr>)
* <elseif-range>
* S;
*
* -- NP(elseif) = NP(<elseif-range>) + NP(<expr>) + 1 --
*
*
* elseif (<expr>)
* <elseif-range>
* else
* <else-range>
* S;
*
* -- NP(if) = NP(<if-range>) + NP(<expr>) + NP(<else-range> --
* </code>
*
* @param ASTElseIfStatement $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitElseIfStatement($node, $data)
{
$npath = $this->sumComplexity($node->getChild(0));
foreach ($node->getChildren() as $child) {
if ($child instanceof ASTStatement) {
$expr = $child->accept($this, '1');
$npath = MathUtil::add($npath, $expr);
}
}
if (!$node->hasElse()) {
$npath = MathUtil::add($npath, '1');
}
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of a for-statement, the
* meassured value is then returned as a string.
*
* <code>
* for (<expr1>; <expr2>; <expr3>)
* <for-range>
* S;
*
* -- NP(for) = NP(<for-range>) + NP(<expr1>) + NP(<expr2>) + NP(<expr3>) + 1 --
* </code>
*
* @param ASTNode $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitForStatement($node, $data)
{
$npath = '1';
foreach ($node->getChildren() as $child) {
if ($child instanceof ASTStatement) {
$stmt = $child->accept($this, '1');
$npath = MathUtil::add($npath, $stmt);
} elseif ($child instanceof ASTExpression) {
$expr = $this->sumComplexity($child);
$npath = MathUtil::add($npath, $expr);
}
}
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of a for-statement, the
* meassured value is then returned as a string.
*
* <code>
* fpreach (<expr>)
* <foreach-range>
* S;
*
* -- NP(foreach) = NP(<foreach-range>) + NP(<expr>) + 1 --
* </code>
*
* @param ASTNode $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitForeachStatement($node, $data)
{
$npath = $this->sumComplexity($node->getChild(0));
$npath = MathUtil::add($npath, '1');
foreach ($node->getChildren() as $child) {
if ($child instanceof ASTStatement) {
$stmt = $child->accept($this, '1');
$npath = MathUtil::add($npath, $stmt);
}
}
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of an if-statement, the
* meassured value is then returned as a string.
*
* <code>
* if (<expr>)
* <if-range>
* S;
*
* -- NP(if) = NP(<if-range>) + NP(<expr>) + 1 --
*
*
* if (<expr>)
* <if-range>
* else
* <else-range>
* S;
*
* -- NP(if) = NP(<if-range>) + NP(<expr>) + NP(<else-range> --
* </code>
*
* @param ASTIfStatement $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitIfStatement($node, $data)
{
$npath = $this->sumComplexity($node->getChild(0));
foreach ($node->getChildren() as $child) {
if ($child instanceof ASTStatement) {
$stmt = $child->accept($this, '1');
$npath = MathUtil::add($npath, $stmt);
}
}
if (!$node->hasElse()) {
$npath = MathUtil::add($npath, '1');
}
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of a return-statement, the
* meassured value is then returned as a string.
*
* <code>
* return <expr>;
*
* -- NP(return) = NP(<expr>) --
* </code>
*
* @param ASTNode $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitReturnStatement($node, $data)
{
if (($npath = $this->sumComplexity($node)) === '0') {
return $data;
}
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of a switch-statement, the
* meassured value is then returned as a string.
*
* <code>
* switch (<expr>)
* <case-range1>
* <case-range2>
* ...
* <default-range>
*
* -- NP(switch) = NP(<expr>) + NP(<default-range>) + NP(<case-range1>) ... --
* </code>
*
* @param ASTNode $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitSwitchStatement($node, $data)
{
$npath = $this->sumComplexity($node->getChild(0));
foreach ($node->getChildren() as $child) {
if ($child instanceof ASTSwitchLabel) {
$label = $child->accept($this, '1');
$npath = MathUtil::add($npath, $label);
}
}
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of a try-catch-statement, the
* meassured value is then returned as a string.
*
* <code>
* try
* <try-range>
* catch
* <catch-range>
*
* -- NP(try) = NP(<try-range>) + NP(<catch-range>) --
*
*
* try
* <try-range>
* catch
* <catch-range1>
* catch
* <catch-range2>
* ...
*
* -- NP(try) = NP(<try-range>) + NP(<catch-range1>) + NP(<catch-range2>) ... --
* </code>
*
* @param ASTNode $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitTryStatement($node, $data)
{
$npath = '0';
foreach ($node->getChildren() as $child) {
if ($child instanceof ASTStatement) {
$stmt = $child->accept($this, '1');
$npath = MathUtil::add($npath, $stmt);
}
}
return MathUtil::mul($npath, $data);
}
/**
* This method calculates the NPath Complexity of a while-statement, the
* meassured value is then returned as a string.
*
* <code>
* while (<expr>)
* <while-range>
* S;
*
* -- NP(while) = NP(<while-range>) + NP(<expr>) + 1 --
* </code>
*
* @param ASTNode $node The currently visited node.
* @param numeric-string $data The previously calculated npath value.
*
* @return numeric-string
*
* @since 0.9.12
*/
public function visitWhileStatement($node, $data)
{
$expr = $this->sumComplexity($node->getChild(0));
$stmt = $node->getChild(1)->accept($this, '1');
$npath = MathUtil::add($expr, $stmt);
$npath = MathUtil::add($npath, '1');
return MathUtil::mul($npath, $data);
}
/**
* Calculates the expression sum of the given node.
*
* @param ASTNode $node The currently visited node.
*
* @return numeric-string
*
* @since 0.9.12
*
* @todo I don't like this method implementation, it should be possible to
* implement this method with more visitor behavior for the boolean
* and logical expressions.
*/
public function sumComplexity($node)
{
$sum = '0';
if ($node instanceof ASTConditionalExpression) {
$sum = MathUtil::add($sum, $node->accept($this, '1'));
} elseif ($node instanceof ASTBooleanAndExpression
|| $node instanceof ASTBooleanOrExpression
|| $node instanceof ASTLogicalAndExpression
|| $node instanceof ASTLogicalOrExpression
|| $node instanceof ASTLogicalXorExpression
) {
$sum = MathUtil::add($sum, '1');
} else {
foreach ($node->getChildren() as $child) {
$expr = $this->sumComplexity($child);
$sum = MathUtil::add($sum, $expr);
}
}
return $sum;
}
}
@@ -0,0 +1,320 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
/**
* This analyzer collects different count metrics for code artifacts like
* classes, methods, functions or namespaces.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class NodeCountAnalyzer extends AbstractAnalyzer implements AnalyzerFilterAware, AnalyzerNodeAware, AnalyzerProjectAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_NUMBER_OF_PACKAGES = 'nop',
M_NUMBER_OF_CLASSES = 'noc',
M_NUMBER_OF_INTERFACES = 'noi',
M_NUMBER_OF_METHODS = 'nom',
M_NUMBER_OF_FUNCTIONS = 'nof';
/**
* Number Of Packages.
*
* @var int
*/
private $nop = 0;
/**
* Number Of Classes.
*
* @var int
*/
private $noc = 0;
/**
* Number Of Interfaces.
*
* @var int
*/
private $noi = 0;
/**
* Number Of Methods.
*
* @var int
*/
private $nom = 0;
/**
* Number Of Functions.
*
* @var int
*/
private $nof = 0;
/**
* Collected node metrics
*
* @var array<string, array<string, int>>
*/
private $nodeMetrics = null;
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b> instance. If there are no metrics for the
* requested node, this method will return an empty <b>array</b>.
*
* <code>
* array(
* 'noc' => 23,
* 'nom' => 17,
* 'nof' => 42
* )
* </code>
*
* @return array<string, mixed>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
$metrics = array();
if (isset($this->nodeMetrics[$artifact->getId()])) {
$metrics = $this->nodeMetrics[$artifact->getId()];
}
return $metrics;
}
/**
* Provides the project summary as an <b>array</b>.
*
* <code>
* array(
* 'nop' => 23,
* 'noc' => 17,
* 'noi' => 23,
* 'nom' => 42,
* 'nof' => 17
* )
* </code>
*
* @return array<string, mixed>
*/
public function getProjectMetrics()
{
return array(
self::M_NUMBER_OF_PACKAGES => $this->nop,
self::M_NUMBER_OF_CLASSES => $this->noc,
self::M_NUMBER_OF_INTERFACES => $this->noi,
self::M_NUMBER_OF_METHODS => $this->nom,
self::M_NUMBER_OF_FUNCTIONS => $this->nof
);
}
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
// Check for previous run
if ($this->nodeMetrics === null) {
$this->fireStartAnalyzer();
$this->nodeMetrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
}
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
if (false === $class->isUserDefined()) {
return;
}
$this->fireStartClass($class);
// Update global class count
++$this->noc;
$id = $class->getNamespace()->getId();
++$this->nodeMetrics[$id][self::M_NUMBER_OF_CLASSES];
$this->nodeMetrics[$class->getId()] = array(
self::M_NUMBER_OF_METHODS => 0
);
foreach ($class->getMethods() as $method) {
$method->accept($this);
}
$this->fireEndClass($class);
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
// Update global function count
++$this->nof;
$id = $function->getNamespace()->getId();
++$this->nodeMetrics[$id][self::M_NUMBER_OF_FUNCTIONS];
$this->fireEndFunction($function);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
if (false === $interface->isUserDefined()) {
return;
}
$this->fireStartInterface($interface);
// Update global class count
++$this->noi;
$id = $interface->getNamespace()->getId();
++$this->nodeMetrics[$id][self::M_NUMBER_OF_INTERFACES];
$this->nodeMetrics[$interface->getId()] = array(
self::M_NUMBER_OF_METHODS => 0
);
foreach ($interface->getMethods() as $method) {
$method->accept($this);
}
$this->fireEndInterface($interface);
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
// Update global method count
++$this->nom;
$parent = $method->getParent();
// Update parent class or interface
$parentId = $parent->getId();
++$this->nodeMetrics[$parentId][self::M_NUMBER_OF_METHODS];
$id = $parent->getNamespace()->getId();
++$this->nodeMetrics[$id][self::M_NUMBER_OF_METHODS];
$this->fireEndMethod($method);
}
/**
* Visits a namespace node.
*
* @return void
*/
public function visitNamespace(ASTNamespace $namespace)
{
$this->fireStartNamespace($namespace);
++$this->nop;
$this->nodeMetrics[$namespace->getId()] = array(
self::M_NUMBER_OF_CLASSES => 0,
self::M_NUMBER_OF_INTERFACES => 0,
self::M_NUMBER_OF_METHODS => 0,
self::M_NUMBER_OF_FUNCTIONS => 0
);
foreach ($namespace->getClasses() as $class) {
$class->accept($this);
}
foreach ($namespace->getInterfaces() as $interface) {
$interface->accept($this);
}
foreach ($namespace->getFunctions() as $function) {
$function->accept($this);
}
$this->fireEndNamespace($namespace);
}
}
@@ -0,0 +1,485 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics\Analyzer;
use PDepend\Metrics\AbstractCachingAnalyzer;
use PDepend\Metrics\AnalyzerFilterAware;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\Tokenizer\Token;
use PDepend\Source\Tokenizer\Tokens;
/**
* This analyzer collects different lines of code metrics.
*
* It collects the total Lines Of Code(<b>loc</b>), the None Comment Lines Of
* Code(<b>ncloc</b>), the Comment Lines Of Code(<b>cloc</b>) and a approximated
* Executable Lines Of Code(<b>eloc</b>) for files, classes, interfaces,
* methods, properties and function.
*
* The current implementation has a limitation, that affects inline comments.
* The following code will suppress one line of code.
*
* <code>
* function foo() {
* foobar(); // Bad behaviour...
* }
* </code>
*
* The same rule applies to class methods. mapi, <b>PLEASE, FIX THIS ISSUE.</b>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class NodeLocAnalyzer extends AbstractCachingAnalyzer implements
AnalyzerNodeAware,
AnalyzerFilterAware,
AnalyzerProjectAware
{
/**
* Metrics provided by the analyzer implementation.
*/
const M_LINES_OF_CODE = 'loc',
M_COMMENT_LINES_OF_CODE = 'cloc',
M_EXECUTABLE_LINES_OF_CODE = 'eloc',
M_LOGICAL_LINES_OF_CODE = 'lloc',
M_NON_COMMENT_LINES_OF_CODE = 'ncloc';
/**
* Collected project metrics.
*
* @var array<string, integer>
*/
private $projectMetrics = array(
self::M_LINES_OF_CODE => 0,
self::M_COMMENT_LINES_OF_CODE => 0,
self::M_EXECUTABLE_LINES_OF_CODE => 0,
self::M_LOGICAL_LINES_OF_CODE => 0,
self::M_NON_COMMENT_LINES_OF_CODE => 0
);
/**
* Executable lines of code in a class. The method calculation increases
* this property with each method's ELOC value.
*
* @var int
*
* @since 0.9.12
*/
private $classExecutableLines = 0;
/**
* Logical lines of code in a class. The method calculation increases this
* property with each method's LLOC value.
*
* @var int
*
* @since 0.9.13
*/
private $classLogicalLines = 0;
/**
* This method will return an <b>array</b> with all generated metric values
* for the given <b>$node</b> instance. If there are no metrics for the
* requested node, this method will return an empty <b>array</b>.
*
* <code>
* array(
* 'loc' => 23,
* 'cloc' => 17,
* 'eloc' => 17,
* 'ncloc' => 42
* )
* </code>
*
* @return array<string, integer>
*/
public function getNodeMetrics(ASTArtifact $artifact)
{
$metrics = array();
if (isset($this->metrics[$artifact->getId()])) {
$metrics = $this->metrics[$artifact->getId()];
}
return $metrics;
}
/**
* Provides the project summary as an <b>array</b>.
*
* <code>
* array(
* 'loc' => 23,
* 'cloc' => 17,
* 'ncloc' => 42
* )
* </code>
*
* @return array<string, integer>
*/
public function getProjectMetrics()
{
return $this->projectMetrics;
}
/**
* Processes all {@link ASTNamespace} code nodes.
*
* @return void
*/
public function analyze($namespaces)
{
if ($this->metrics === null) {
$this->loadCache();
$this->fireStartAnalyzer();
$this->metrics = array();
foreach ($namespaces as $namespace) {
$namespace->accept($this);
}
$this->fireEndAnalyzer();
$this->unloadCache();
}
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
$this->fireStartClass($class);
$class->getCompilationUnit()->accept($this);
$this->classExecutableLines = 0;
$this->classLogicalLines = 0;
foreach ($class->getMethods() as $method) {
$method->accept($this);
}
if ($this->restoreFromCache($class)) {
$this->fireEndClass($class);
return;
}
list($cloc) = $this->linesOfCode($class->getTokens(), true);
$loc = $class->getEndLine() - $class->getStartLine() + 1;
$ncloc = $loc - $cloc;
$this->metrics[$class->getId()] = array(
self::M_LINES_OF_CODE => $loc,
self::M_COMMENT_LINES_OF_CODE => $cloc,
self::M_EXECUTABLE_LINES_OF_CODE => $this->classExecutableLines,
self::M_LOGICAL_LINES_OF_CODE => $this->classLogicalLines,
self::M_NON_COMMENT_LINES_OF_CODE => $ncloc,
);
$this->fireEndClass($class);
}
/**
* Visits a file node.
*
* @return void
*/
public function visitCompilationUnit(ASTCompilationUnit $compilationUnit)
{
// Skip for dummy files
if ($compilationUnit->getFileName() === null) {
return;
}
// Check for initial file
$id = $compilationUnit->getId();
if (!$id || isset($this->metrics[$id])) {
return;
}
$this->fireStartFile($compilationUnit);
if ($this->restoreFromCache($compilationUnit)) {
$this->updateProjectMetrics($id);
$this->fireEndFile($compilationUnit);
return;
}
list($cloc, $eloc, $lloc) = $this->linesOfCode($compilationUnit->getTokens());
$loc = $compilationUnit->getEndLine();
$ncloc = $loc - $cloc;
$this->metrics[$id] = array(
self::M_LINES_OF_CODE => $loc,
self::M_COMMENT_LINES_OF_CODE => $cloc,
self::M_EXECUTABLE_LINES_OF_CODE => $eloc,
self::M_LOGICAL_LINES_OF_CODE => $lloc,
self::M_NON_COMMENT_LINES_OF_CODE => $ncloc
);
$this->updateProjectMetrics($id);
$this->fireEndFile($compilationUnit);
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$this->fireStartFunction($function);
$function->getCompilationUnit()->accept($this);
if ($this->restoreFromCache($function)) {
$this->fireEndFunction($function);
return;
}
list($cloc, $eloc, $lloc) = $this->linesOfCode(
$function->getTokens(),
true
);
$loc = $function->getEndLine() - $function->getStartLine() + 1;
$ncloc = $loc - $cloc;
$this->metrics[$function->getId()] = array(
self::M_LINES_OF_CODE => $loc,
self::M_COMMENT_LINES_OF_CODE => $cloc,
self::M_EXECUTABLE_LINES_OF_CODE => $eloc,
self::M_LOGICAL_LINES_OF_CODE => $lloc,
self::M_NON_COMMENT_LINES_OF_CODE => $ncloc
);
$this->fireEndFunction($function);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
$this->fireStartInterface($interface);
$interface->getCompilationUnit()->accept($this);
foreach ($interface->getMethods() as $method) {
$method->accept($this);
}
if ($this->restoreFromCache($interface)) {
$this->fireEndInterface($interface);
return;
}
list($cloc) = $this->linesOfCode($interface->getTokens(), true);
$loc = $interface->getEndLine() - $interface->getStartLine() + 1;
$ncloc = $loc - $cloc;
$this->metrics[$interface->getId()] = array(
self::M_LINES_OF_CODE => $loc,
self::M_COMMENT_LINES_OF_CODE => $cloc,
self::M_EXECUTABLE_LINES_OF_CODE => 0,
self::M_LOGICAL_LINES_OF_CODE => 0,
self::M_NON_COMMENT_LINES_OF_CODE => $ncloc
);
$this->fireEndInterface($interface);
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$this->fireStartMethod($method);
if ($this->restoreFromCache($method)) {
$this->fireEndMethod($method);
return;
}
if ($method->isAbstract()) {
$cloc = 0;
$eloc = 0;
$lloc = 0;
} else {
list($cloc, $eloc, $lloc) = $this->linesOfCode(
$method->getTokens(),
true
);
}
$loc = $method->getEndLine() - $method->getStartLine() + 1;
$ncloc = $loc - $cloc;
$this->metrics[$method->getId()] = array(
self::M_LINES_OF_CODE => $loc,
self::M_COMMENT_LINES_OF_CODE => $cloc,
self::M_EXECUTABLE_LINES_OF_CODE => $eloc,
self::M_LOGICAL_LINES_OF_CODE => $lloc,
self::M_NON_COMMENT_LINES_OF_CODE => $ncloc
);
$this->classExecutableLines += $eloc;
$this->classLogicalLines += $lloc;
$this->fireEndMethod($method);
}
/**
* Updates the project metrics based on the node metrics identifier by the
* given <b>$id</b>.
*
* @param string $id The unique identifier of a node.
*
* @return void
*/
private function updateProjectMetrics($id)
{
foreach ($this->metrics[$id] as $metric => $value) {
$this->projectMetrics[$metric] += $value;
}
}
/**
* Counts the Comment Lines Of Code (CLOC) and a pseudo Executable Lines Of
* Code (ELOC) values.
*
* ELOC = Non Whitespace Lines + Non Comment Lines
*
* <code>
* array(
* 0 => 23, // Comment Lines Of Code
* 1 => 42 // Executable Lines Of Code
* )
* </code>
*
* @param array<int, Token> $tokens The raw token stream.
* @param bool $search Optional boolean flag, search start.
*
* @return array<int, integer>
*/
private function linesOfCode(array $tokens, $search = false)
{
$clines = array();
$elines = array();
$llines = 0;
$count = count($tokens);
if ($search === true) {
for ($i = 0; $i < $count; ++$i) {
$token = $tokens[$i];
if ($token->type === Tokens::T_CURLY_BRACE_OPEN) {
break;
}
}
} else {
$i = 0;
}
for (; $i < $count; ++$i) {
$token = $tokens[$i];
if ($token->type === Tokens::T_COMMENT
|| $token->type === Tokens::T_DOC_COMMENT
) {
$lines =& $clines;
} else {
$lines =& $elines;
}
switch ($token->type) {
// These statement are terminated by a semicolon
//case Tokens::T_RETURN:
//case Tokens::T_THROW:
case Tokens::T_IF:
case Tokens::T_TRY:
case Tokens::T_CASE:
case Tokens::T_GOTO:
case Tokens::T_CATCH:
case Tokens::T_WHILE:
case Tokens::T_ELSEIF:
case Tokens::T_SWITCH:
case Tokens::T_DEFAULT:
case Tokens::T_FOREACH:
case Tokens::T_FUNCTION:
case Tokens::T_SEMICOLON:
++$llines;
break;
case Tokens::T_DO:
case Tokens::T_FOR:
// Because statements at least require one semicolon
--$llines;
break;
}
if ($token->startLine === $token->endLine) {
$lines[$token->startLine] = true;
} else {
for ($j = $token->startLine; $j <= $token->endLine; ++$j) {
$lines[$j] = true;
}
}
unset($lines);
}
return array(count($clines), count($elines), $llines);
}
}
@@ -0,0 +1,67 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
namespace PDepend\Metrics;
use PDepend\Util\Cache\CacheDriver;
/**
* Simple marker interface that is used to mark an analyzer as cache aware. This
* means that the loading infrastructure code will inject an instance of
* {@link CacheDriver} into this analyzer.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
interface AnalyzerCacheAware extends Analyzer
{
/**
* Setter method for the system wide used cache.
*
* @return void
*/
public function setCache(CacheDriver $cache);
}
@@ -0,0 +1,88 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
use PDepend\Report\ReportGenerator;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Creates Analyzer instances
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class AnalyzerFactory
{
/**
* @var ContainerInterface
*/
private $container;
/**
* Create a new Analyzer Factory
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Create and configure all analyzers required for given set of loggers.
*
* @param ReportGenerator[] $generators
*
* @return Analyzer[]
*/
public function createRequiredForGenerators(array $generators)
{
$analyzers = array();
foreach ($generators as $logger) {
foreach ($logger->getAcceptedAnalyzers() as $type) {
$analyzers[$type] = $this->container->get($type);
}
}
return $analyzers;
}
}
@@ -0,0 +1,56 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
/**
* Simple marker interface that is used to mark an analyzer as namespace filter
* aware. This means that a defined namespace filter for external dependencies
* on namespaces an its classes and interfaces must be set before this analyzer
* starts.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface AnalyzerFilterAware extends Analyzer
{
}
@@ -0,0 +1,82 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.10
*/
namespace PDepend\Metrics;
use ArrayIterator;
use FilterIterator;
use ReturnTypeWillChange;
/**
* Filter iterator that only returns enabled {@link Analyzer}
* instances.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.10
*/
class AnalyzerIterator extends FilterIterator
{
/**
* Constructs a new iterator instance.
*
* @param Analyzer[] $analyzers
*/
public function __construct(array $analyzers)
{
parent::__construct(new ArrayIterator($analyzers));
}
/**
* Returns <b>true</b> when the current analyzer instance is enabled.
*
* @return bool
*/
#[ReturnTypeWillChange]
public function accept()
{
return $this->getInnerIterator()->current()->isEnabled();
}
}
@@ -0,0 +1,73 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
use PDepend\Source\ASTVisitor\ASTVisitListener;
/**
* An implementation of this listener can be used to recieve informations about
* the current metric analyzer.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface AnalyzerListener extends ASTVisitListener
{
/**
* This method is called when the analyzer starts code processing.
*
* @param Analyzer $analyzer The context analyzer instance.
*
* @return void
*/
public function startAnalyzer(Analyzer $analyzer);
/**
* This method is called when the analyzer has finished code processing.
*
* @param Analyzer $analyzer The context analyzer instance.
*
* @return void
*/
public function endAnalyzer(Analyzer $analyzer);
}
@@ -0,0 +1,71 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
use PDepend\Source\AST\ASTArtifact;
/**
* Marker interface that marks a result set as node metrics aware.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface AnalyzerNodeAware extends Analyzer
{
/**
* This method will return an <b>array</b> with all generated metric values
* for the node with the given <b>$id</b> identifier. If there are no
* metrics for the requested node, this method will return an empty <b>array</b>.
*
* <code>
* array(
* 'loc' => 42,
* 'ncloc' => 17,
* 'cc' => 12
* )
* </code>
*
* @return array<string, mixed>
*/
public function getNodeMetrics(ASTArtifact $artifact);
}
@@ -0,0 +1,70 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Metrics;
/**
* This interface is used to mark a result set as project summary aware.
*
* A result set that implements this interface provides overview or calculated
* values for the complete analyzed source code.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface AnalyzerProjectAware extends Analyzer
{
/**
* Provides the project summary as an <b>array</b>.
*
* <code>
* array(
* 'loc' => 1742,
* 'nop' => 23,
* 'noc' => 17
* )
* </code>
*
* @return array<string, mixed>
*/
public function getProjectMetrics();
}
@@ -0,0 +1,120 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend;
// @codeCoverageIgnoreStart
use PDepend\Metrics\AnalyzerListener;
use PDepend\Source\ASTVisitor\ASTVisitListener;
use PDepend\Source\Builder\Builder;
use PDepend\Source\Tokenizer\Tokenizer;
/**
* This listener can be used to get informations about the current pdepend process.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface ProcessListener extends ASTVisitListener, AnalyzerListener
{
/**
* Is called when PDepend starts the file parsing process.
*
* @param Builder<mixed> $builder The used node builder instance.
*
* @return void
*/
public function startParseProcess(Builder $builder);
/**
* Is called when PDepend has finished the file parsing process.
*
* @param Builder<mixed> $builder The used node builder instance.
*
* @return void
*/
public function endParseProcess(Builder $builder);
/**
* Is called when PDepend starts parsing of a new file.
*
* @return void
*/
public function startFileParsing(Tokenizer $tokenizer);
/**
* Is called when PDepend has finished a file.
*
* @return void
*/
public function endFileParsing(Tokenizer $tokenizer);
/**
* Is called when PDepend starts the analyzing process.
*
* @return void
*/
public function startAnalyzeProcess();
/**
* Is called when PDepend has finished the analyzing process.
*
* @return void
*/
public function endAnalyzeProcess();
/**
* Is called when PDepend starts the logging process.
*
* @return void
*/
public function startLogProcess();
/**
* Is called when PDepend has finished the logging process.
*
* @return void
*/
public function endLogProcess();
}
// @codeCoverageIgnoreEnd
@@ -0,0 +1,64 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTNamespace;
/**
* A logger that implements this interface needs the analyzed code structure.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface CodeAwareGenerator extends ReportGenerator
{
/**
* Sets the context code nodes.
*
* @param ASTArtifactList<ASTNamespace> $artifacts
*
* @return void
*/
public function setArtifacts(ASTArtifactList $artifacts);
}
@@ -0,0 +1,356 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report\Dependencies;
use DOMDocument;
use DOMElement;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\ClassDependencyAnalyzer;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\Utf8Util;
/**
* This logger generates a summary xml document with aggregated project, class,
* method and file dependencies.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Xml extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
/**
* The log output file.
*
* @var string
*/
private $logFile = null;
/**
* The raw {@link ASTNamespace} instances.
*
* @var ASTArtifactList<ASTNamespace>
*/
protected $code = null;
/**
* Set of all analyzed files.
*
* @var ASTCompilationUnit[]
*/
protected $fileSet = array();
/**
* @var ClassDependencyAnalyzer|null
*/
private $dependencyAnalyzer;
/**
* The internal used xml stack.
*
* @var DOMElement[]
*/
private $xmlStack = array();
/**
* Sets the output log file.
*
* @param string $logFile The output log file.
*
* @return void
*/
public function setLogFile($logFile)
{
$this->logFile = $logFile;
}
/**
* Returns an <b>array</b> with accepted analyzer types. These types can be
* concrete analyzer classes or one of the descriptive analyzer interfaces.
*
* @return array<string>
*/
public function getAcceptedAnalyzers()
{
return array(
'pdepend.analyzer.class_dependency',
);
}
/**
* Sets the context code nodes.
*
* @param ASTArtifactList<ASTNamespace> $artifacts
*
* @return void
*/
public function setArtifacts(ASTArtifactList $artifacts)
{
$this->code = $artifacts;
}
/**
* Adds an analyzer to log. If this logger accepts the given analyzer it
* with return <b>true</b>, otherwise the return value is <b>false</b>.
*
* @param Analyzer $analyzer The analyzer to log.
*
* @return bool
*/
public function log(Analyzer $analyzer)
{
if ($analyzer instanceof ClassDependencyAnalyzer) {
$this->dependencyAnalyzer = $analyzer;
return true;
}
return false;
}
/**
* Closes the logger process and writes the output file.
*
* @throws NoLogOutputException If the no log target exists.
*
* @return void
*/
public function close()
{
if ($this->logFile === null) {
throw new NoLogOutputException($this);
}
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$dependencies = $dom->createElement('dependencies');
$dependencies->setAttribute('generated', date('Y-m-d\TH:i:s'));
$dependencies->setAttribute('pdepend', '@package_version@');
array_push($this->xmlStack, $dependencies);
foreach ($this->code as $node) {
$node->accept($this);
}
$dom->appendChild($dependencies);
$buffer = $dom->saveXML();
file_put_contents($this->logFile, $buffer);
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
$this->generateTypeXml($class, 'class');
}
/**
* Visits a trait node.
*
* @return void
*/
public function visitTrait(ASTTrait $trait)
{
$this->generateTypeXml($trait, 'trait');
}
/**
* Generates the XML for a class or trait node.
*
* @param string $typeIdentifier
*
* @return void
*/
private function generateTypeXml(AbstractASTClassOrInterface $type, $typeIdentifier)
{
if (!$type->isUserDefined()) {
return;
}
$xml = end($this->xmlStack);
if (!$xml) {
return;
}
$doc = $xml->ownerDocument;
$typeXml = $doc->createElement($typeIdentifier);
$typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));
$xml->appendChild($typeXml);
array_push($this->xmlStack, $typeXml);
$this->writeNodeDependencies($typeXml, $type);
$this->writeFileReference($typeXml, $type->getCompilationUnit());
array_pop($this->xmlStack);
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
// Do not care
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
$this->generateTypeXml($interface, 'interface');
}
/**
* Visits a namespace node.
*
* @return void
*/
public function visitNamespace(ASTNamespace $namespace)
{
$xml = end($this->xmlStack);
if (!$xml) {
return;
}
$doc = $xml->ownerDocument;
$packageXml = $doc->createElement('package');
$packageXml->setAttribute('name', Utf8Util::ensureEncoding($namespace->getName()));
array_push($this->xmlStack, $packageXml);
foreach ($namespace->getTypes() as $type) {
$type->accept($this);
}
foreach ($namespace->getFunctions() as $function) {
$function->accept($this);
}
array_pop($this->xmlStack);
if ($packageXml->firstChild === null) {
return;
}
$xml->appendChild($packageXml);
}
/**
* Aggregates all dependencies for the given <b>$node</b> instance and adds them
* to the <b>\DOMElement</b>
*
* @return void
*/
protected function writeNodeDependencies(DOMElement $xml, AbstractASTArtifact $node)
{
if (!$this->dependencyAnalyzer) {
return;
}
$doc = $xml->ownerDocument;
$efferentXml = $doc->createElement('efferent');
$xml->appendChild($efferentXml);
foreach ($this->dependencyAnalyzer->getEfferents($node) as $type) {
$typeXml = $doc->createElement('type');
$typeXml->setAttribute('namespace', Utf8Util::ensureEncoding($type->getNamespaceName()));
$typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));
$efferentXml->appendChild($typeXml);
}
$afferentXml = $doc->createElement('afferent');
$xml->appendChild($afferentXml);
foreach ($this->dependencyAnalyzer->getAfferents($node) as $type) {
$typeXml = $doc->createElement('type');
$typeXml->setAttribute('namespace', Utf8Util::ensureEncoding($type->getNamespaceName()));
$typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));
$afferentXml->appendChild($typeXml);
}
}
/**
* Appends a file reference element to the given <b>$xml</b> element.
*
* <code>
* <class name="\PDepend\Engine">
* <file name="PDepend/Engine.php" />
* </class>
* </code>
*
* @param DOMElement $xml The parent xml element.
* @param ASTCompilationUnit $compilationUnit The code file instance.
*
* @return void
*/
protected function writeFileReference(DOMElement $xml, ASTCompilationUnit $compilationUnit = null)
{
if (in_array($compilationUnit, $this->fileSet, true) === false) {
$this->fileSet[] = $compilationUnit;
}
$fileXml = $xml->ownerDocument->createElement('file');
$fileXml->setAttribute('name', Utf8Util::ensureEncoding($compilationUnit->getFileName()));
$xml->appendChild($fileXml);
}
}
@@ -0,0 +1,61 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report;
/**
* Marker interface for a log file aware logger.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface FileAwareGenerator extends ReportGenerator
{
/**
* Sets the output log file.
*
* @param string $logFile The output log file.
*
* @return void
*/
public function setLogFile($logFile);
}
@@ -0,0 +1,267 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report\Jdepend;
use DOMDocument;
use DOMElement;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\DependencyAnalyzer;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\FileUtil;
use PDepend\Util\ImageConvert;
use PDepend\Util\Utf8Util;
/**
* Generates a chart with the aggregated metrics.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Chart extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
/**
* The output file name.
*
* @var string
*/
private $logFile = null;
/**
* The context source code.
*
* @var ASTArtifactList<ASTNamespace>
*/
private $code = null;
/**
* The context analyzer instance.
*
* @var Analyzer\DependencyAnalyzer
*/
private $analyzer = null;
/**
* Sets the output log file.
*
* @param string $logFile The output log file.
*
* @return void
*/
public function setLogFile($logFile)
{
$this->logFile = $logFile;
}
/**
* Returns an <b>array</b> with accepted analyzer types. These types can be
* concrete analyzer classes or one of the descriptive analyzer interfaces.
*
* @return array<string>
*/
public function getAcceptedAnalyzers()
{
return array('pdepend.analyzer.dependency');
}
/**
* Sets the context code nodes.
*
* @param ASTArtifactList<ASTNamespace> $artifacts
*
* @return void
*/
public function setArtifacts(ASTArtifactList $artifacts)
{
$this->code = $artifacts;
}
/**
* Adds an analyzer to log. If this logger accepts the given analyzer it
* with return <b>true</b>, otherwise the return value is <b>false</b>.
*
* @param Analyzer $analyzer The analyzer to log.
*
* @return bool
*/
public function log(Analyzer $analyzer)
{
if ($analyzer instanceof DependencyAnalyzer) {
$this->analyzer = $analyzer;
return true;
}
return false;
}
/**
* Closes the logger process and writes the output file.
*
* @throws NoLogOutputException If the no log target exists.
*
* @return void
*/
public function close()
{
// Check for configured log file
if ($this->logFile === null) {
throw new NoLogOutputException($this);
}
$bias = 0.1;
$svg = new DOMDocument('1.0', 'UTF-8');
$svg->loadXML(file_get_contents(dirname(__FILE__) . '/chart.svg'));
$layer = $svg->getElementById('jdepend.layer');
$bad = $svg->getElementById('jdepend.bad');
$bad->removeAttribute('xml:id');
$good = $svg->getElementById('jdepend.good');
$good->removeAttribute('xml:id');
$legendTemplate = $svg->getElementById('jdepend.legend');
$legendTemplate->removeAttribute('xml:id');
foreach ($this->getItems() as $item) {
$element = $item['distance'] < $bias ? $good : $bad;
$ellipse = $element->cloneNode(true);
if (!$ellipse instanceof DOMElement) {
continue;
}
$a = $item['ratio'] / 15;
$e = (50 - $item['ratio']) + ($item['abstraction'] * 320);
$f = (20 - $item['ratio'] + 190) - ($item['instability'] * 190);
$transform = "matrix({$a}, 0, 0, {$a}, {$e}, {$f})";
$ellipse->setAttribute('id', uniqid('pdepend_'));
$ellipse->setAttribute('title', $item['name']);
$ellipse->setAttribute('transform', $transform);
$layer->appendChild($ellipse);
$result = preg_match('#\\\\([^\\\\]+)$#', $item['name'], $found);
if ($result && count($found)) {
$angle = rand(0, 314) / 100 - 1.57;
$legend = $legendTemplate->cloneNode(true);
if ($legend instanceof DOMElement) {
$legend->setAttribute('x', (string)($e + $item['ratio'] * (1 + cos($angle))));
$legend->setAttribute('y', (string)($f + $item['ratio'] * (1 + sin($angle))));
$legend->nodeValue = $found[1];
$legendTemplate->parentNode->appendChild($legend);
}
}
}
$bad->parentNode->removeChild($bad);
$good->parentNode->removeChild($good);
$legendTemplate->parentNode->removeChild($legendTemplate);
$temp = FileUtil::getSysTempDir();
$temp .= '/' . uniqid('pdepend_') . '.svg';
$svg->save($temp);
ImageConvert::convert($temp, $this->logFile);
// Remove temp file
unlink($temp);
}
/**
* @return array<int, array<string, mixed>>
*/
private function getItems()
{
$items = array();
foreach ($this->code as $namespace) {
if (!$namespace->isUserDefined()) {
continue;
}
$metrics = $this->analyzer->getStats($namespace);
if (count($metrics) === 0) {
continue;
}
$items[] = array(
'size' => $metrics['cc'] + $metrics['ac'],
'abstraction' => $metrics['a'],
'instability' => $metrics['i'],
'distance' => $metrics['d'],
'name' => Utf8Util::ensureEncoding($namespace->getName())
);
}
// Sort items by size
usort(
$items,
function ($a, $b) {
return ($a['size'] - $b['size']);
}
);
if ($items) {
$max = $items[count($items) - 1]['size'];
$min = $items[0]['size'];
$diff = (($max - $min) / 10);
foreach ($items as &$item) {
$item['ratio'] = 15;
if ($diff !== 0) {
$item['ratio'] = 5 + (($item['size'] - $min) / $diff);
}
}
}
return $items;
}
}
@@ -0,0 +1,377 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report\Jdepend;
use DOMDocument;
use DOMElement;
use DOMNode;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\DependencyAnalyzer;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\Utf8Util;
/**
* Generates an xml document with the aggregated metrics. The format is borrowed
* from <a href="http://clarkware.com/software/JDepend.html">JDepend</a>.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Xml extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
/**
* The output log file.
*
* @var string
*/
private $logFile = null;
/**
* The raw {@link ASTNamespace} instances.
*
* @var ASTArtifactList<ASTNamespace>
*/
protected $code = null;
/**
* Set of all analyzed files.
*
* @var ASTCompilationUnit[]
*/
protected $fileSet = array();
/**
* List of all generated project metrics.
*
* @var array<string, mixed>
*/
protected $projectMetrics = array();
/**
* List of all collected node metrics.
*
* @var array<string, array<string, array<int, string>>>
*/
protected $nodeMetrics = array();
/**
* The dependency result set.
*
* @var DependencyAnalyzer
*/
protected $analyzer = null;
/**
* The Packages dom element.
*
* @var DOMNode
*/
protected $packages = null;
/**
* The Cycles dom element.
*
* @var DOMNode
*/
protected $cycles = null;
/**
* The concrete classes element for the current package.
*
* @var DOMElement
*/
protected $concreteClasses = null;
/**
* The abstract classes element for the current package.
*
* @var DOMElement
*/
protected $abstractClasses = null;
/**
* Sets the output log file.
*
* @param string $logFile The output log file.
*
* @return void
*/
public function setLogFile($logFile)
{
$this->logFile = $logFile;
}
/**
* Returns an <b>array</b> with accepted analyzer types. These types can be
* concrete analyzer classes or one of the descriptive analyzer interfaces.
*
* @return array<string>
*/
public function getAcceptedAnalyzers()
{
return array('pdepend.analyzer.dependency');
}
/**
* Sets the context code nodes.
*
* @param ASTArtifactList<ASTNamespace> $artifacts
*
* @return void
*/
public function setArtifacts(ASTArtifactList $artifacts)
{
$this->code = $artifacts;
}
/**
* Adds an analyzer to log. If this logger accepts the given analyzer it
* with return <b>true</b>, otherwise the return value is <b>false</b>.
*
* @param Analyzer $analyzer The analyzer to log.
*
* @return bool
*/
public function log(Analyzer $analyzer)
{
if ($analyzer instanceof DependencyAnalyzer) {
$this->analyzer = $analyzer;
return true;
}
return false;
}
/**
* Closes the logger process and writes the output file.
*
* @throws NoLogOutputException If the no log target exists.
*
* @return void
*/
public function close()
{
// Check for configured output
if ($this->logFile === null) {
throw new NoLogOutputException($this);
}
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$jdepend = $dom->createElement('PDepend');
$this->packages = $jdepend->appendChild($dom->createElement('Packages'));
$this->cycles = $jdepend->appendChild($dom->createElement('Cycles'));
foreach ($this->code as $node) {
$node->accept($this);
}
$dom->appendChild($jdepend);
$buffer = $dom->saveXML();
file_put_contents($this->logFile, $buffer);
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
if (!$class->isUserDefined()) {
return;
}
$doc = $this->packages->ownerDocument;
$classXml = $doc->createElement('Class');
$classXml->setAttribute('sourceFile', (string) $class->getCompilationUnit());
$classXml->appendChild(
$doc->createTextNode(
Utf8Util::ensureEncoding($class->getName())
)
);
if ($class->isAbstract()) {
$this->abstractClasses->appendChild($classXml);
} else {
$this->concreteClasses->appendChild($classXml);
}
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
if (!$interface->isUserDefined()) {
return;
}
$doc = $this->abstractClasses->ownerDocument;
$classXml = $doc->createElement('Class');
$classXml->setAttribute('sourceFile', (string) $interface->getCompilationUnit());
$classXml->appendChild(
$doc->createTextNode(
Utf8Util::ensureEncoding($interface->getName())
)
);
$this->abstractClasses->appendChild($classXml);
}
/**
* Visits a package node.
*
* @return void
*/
public function visitNamespace(ASTNamespace $namespace)
{
if (!$namespace->isUserDefined()) {
return;
}
$stats = $this->analyzer->getStats($namespace);
if (count($stats) === 0) {
return;
}
$doc = $this->packages->ownerDocument;
$this->concreteClasses = $doc->createElement('ConcreteClasses');
$this->abstractClasses = $doc->createElement('AbstractClasses');
$packageXml = $doc->createElement('Package');
$packageXml->setAttribute('name', Utf8Util::ensureEncoding($namespace->getName()));
$statsXml = $doc->createElement('Stats');
$statsXml->appendChild($doc->createElement('TotalClasses'))
->appendChild($doc->createTextNode($stats['tc']));
$statsXml->appendChild($doc->createElement('ConcreteClasses'))
->appendChild($doc->createTextNode($stats['cc']));
$statsXml->appendChild($doc->createElement('AbstractClasses'))
->appendChild($doc->createTextNode($stats['ac']));
$statsXml->appendChild($doc->createElement('Ca'))
->appendChild($doc->createTextNode($stats['ca']));
$statsXml->appendChild($doc->createElement('Ce'))
->appendChild($doc->createTextNode($stats['ce']));
$statsXml->appendChild($doc->createElement('A'))
->appendChild($doc->createTextNode($stats['a']));
$statsXml->appendChild($doc->createElement('I'))
->appendChild($doc->createTextNode($stats['i']));
$statsXml->appendChild($doc->createElement('D'))
->appendChild($doc->createTextNode($stats['d']));
$dependsUpon = $doc->createElement('DependsUpon');
foreach ($this->analyzer->getEfferents($namespace) as $efferent) {
$efferentXml = $doc->createElement('Package');
$efferentXml->appendChild(
$doc->createTextNode(
Utf8Util::ensureEncoding($efferent->getName())
)
);
$dependsUpon->appendChild($efferentXml);
}
$usedBy = $doc->createElement('UsedBy');
foreach ($this->analyzer->getAfferents($namespace) as $afferent) {
$afferentXml = $doc->createElement('Package');
$afferentXml->appendChild(
$doc->createTextNode(
Utf8Util::ensureEncoding($afferent->getName())
)
);
$usedBy->appendChild($afferentXml);
}
$packageXml->appendChild($statsXml);
$packageXml->appendChild($this->concreteClasses);
$packageXml->appendChild($this->abstractClasses);
$packageXml->appendChild($dependsUpon);
$packageXml->appendChild($usedBy);
if (($cycles = $this->analyzer->getCycle($namespace)) !== null) {
$cycleXml = $doc->createElement('Package');
$cycleXml->setAttribute('Name', Utf8Util::ensureEncoding($namespace->getName()));
foreach ($cycles as $cycle) {
$cycleXml->appendChild($doc->createElement('Package'))
->appendChild(
$doc->createTextNode(
Utf8Util::ensureEncoding($cycle->getName())
)
);
}
$this->cycles->appendChild($cycleXml);
}
foreach ($namespace->getTypes() as $type) {
$type->accept($this);
}
if ($this->concreteClasses->firstChild === null
&& $this->abstractClasses->firstChild === null
) {
return;
}
$this->packages->appendChild($packageXml);
}
}
@@ -0,0 +1,587 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="390"
height="250"
id="svg2924"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docname="chart.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs2926">
<linearGradient
id="Definition_LinearGradient_76_64_78_66_b3ff4400_619e2400">
<stop
offset="0"
style="stop-color: #b3ff44; stop-opacity: 1.00;"
id="stop24" />
<stop
offset="1"
style="stop-color: #619e24; stop-opacity: 1.00;"
id="stop26" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#Definition_LinearGradient_76_64_78_66_b3ff4400_619e2400"
id="linearGradient2905"
gradientUnits="userSpaceOnUse"
x1="76.3702"
y1="64.2934"
x2="78.8554"
y2="66.7786" />
<linearGradient
id="Definition_LinearGradient_318_84_320_87_ff9d0000_ac550000">
<stop
offset="0"
style="stop-color: #ff9d00; stop-opacity: 1.00;"
id="stop156" />
<stop
offset="1"
style="stop-color: #ac5500; stop-opacity: 1.00;"
id="stop158" />
</linearGradient>
<linearGradient
inkscape:collect="always"
xlink:href="#Definition_LinearGradient_318_84_320_87_ff9d0000_ac550000"
id="jdepend.bad.gradient"
gradientUnits="userSpaceOnUse"
x1="0"
y1="15"
x2="15"
y2="30" />
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective2932" />
<linearGradient
inkscape:collect="always"
xlink:href="#Definition_LinearGradient_76_64_78_66_b3ff4400_619e2400"
id="jdepend.good.gradient"
gradientUnits="userSpaceOnUse"
x1="0"
y1="15"
x2="15"
y2="30" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.5"
inkscape:cx="138.95468"
inkscape:cy="125"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="753"
inkscape:window-x="0"
inkscape:window-y="46" />
<metadata
id="metadata2929">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
xml:id="jdepend.layer">
<rect
style="opacity:1;fill:#4e9a06;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4614"
width="373.00024"
height="1.0000018"
x="53.196194"
y="-9.293786"
transform="matrix(0.8604851,0.5094756,-0.5094738,0.8604862,0,0)" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4464"
width="0.99999946"
height="201"
x="82"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4466"
width="0.99999946"
height="201"
x="113.99999"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4468"
width="0.99999946"
height="201"
x="146"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4470"
width="0.99999946"
height="201"
x="177.99998"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4472"
width="0.99999946"
height="201"
x="209.99998"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4474"
width="0.99999946"
height="201"
x="241.99998"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4476"
width="0.99999946"
height="201"
x="274"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4478"
width="0.99999946"
height="201"
x="305.99997"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4480"
width="0.99999946"
height="201"
x="337.99997"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4482"
width="0.99999946"
height="201"
x="369.99997"
y="19.000061"
rx="0"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4484"
width="331"
height="1"
x="40"
y="19.000025" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4486"
width="331"
height="1"
x="40"
y="57.000023" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4488"
width="331"
height="1"
x="40"
y="38.000023" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4490"
width="331"
height="1"
x="40"
y="76.000023" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4492"
width="331"
height="1"
x="40"
y="95.000023" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4494"
width="331"
height="1"
x="40"
y="133.00003" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4496"
width="331"
height="1"
x="40"
y="114.00002" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4498"
width="331"
height="1"
x="40"
y="152.00005" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4500"
width="331"
height="1"
x="40"
y="171.00005" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4502"
width="331"
height="1"
x="40"
y="190.00006" />
<rect
style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4504"
width="331"
height="1"
x="40"
y="209.00006" />
<rect
style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4462"
width="0.99999946"
height="201"
x="49.999996"
y="19.000061"
rx="0"
ry="0" />
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="83.181007"
y="231.87305"
id="text4506"><tspan
sodipodi:role="line"
id="tspan4508"
x="83.181007"
y="231.87305">0.1</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="114.70088"
y="231.87305"
id="text4510"><tspan
sodipodi:role="line"
id="tspan4512"
x="114.70088"
y="231.87305">0.2</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="242.95323"
y="231.87305"
id="text4514"><tspan
sodipodi:role="line"
id="tspan4516"
x="242.95323"
y="231.87305">0.6</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="210.84497"
y="231.87305"
id="text4518"><tspan
sodipodi:role="line"
id="tspan4520"
x="210.84497"
y="231.87305">0.5</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="178.72696"
y="231.87305"
id="text4522"><tspan
sodipodi:role="line"
id="tspan4524"
x="178.72696"
y="231.87305">0.4</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="146.74567"
y="231.87305"
id="text4526"><tspan
sodipodi:role="line"
id="tspan4528"
x="146.74567"
y="231.87305">0.3</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="307.16241"
y="231.87305"
id="text4530"><tspan
sodipodi:role="line"
id="tspan4532"
x="307.16241"
y="231.87305">0.8</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="275.07858"
y="231.87305"
id="text4534"><tspan
sodipodi:role="line"
id="tspan4536"
x="275.07858"
y="231.87305">0.7</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="371.16162"
y="231.87305"
id="text4538"><tspan
sodipodi:role="line"
id="tspan4540"
x="371.16162"
y="231.87305">1.0</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="339.25113"
y="231.87305"
id="text4542"><tspan
sodipodi:role="line"
id="tspan4544"
x="339.25113"
y="231.87305">0.9</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="50.533203"
y="231.87305"
id="text4546"><tspan
sodipodi:role="line"
id="tspan4548"
x="50.533203"
y="231.87305">0.0</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="193.87793"
id="text4550"><tspan
sodipodi:role="line"
id="tspan4552"
x="28.533201"
y="193.87793">0.1</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="174.87793"
id="text4554"><tspan
sodipodi:role="line"
id="tspan4556"
x="28.533201"
y="174.87793">0.2</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="98.87793"
id="text4558"><tspan
sodipodi:role="line"
id="tspan4560"
x="28.533201"
y="98.87793">0.6</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="117.87792"
id="text4562"><tspan
sodipodi:role="line"
id="tspan4564"
x="28.533201"
y="117.87792">0.5</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="136.87793"
id="text4566"><tspan
sodipodi:role="line"
id="tspan4568"
x="28.533201"
y="136.87793">0.4</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="155.87793"
id="text4570"><tspan
sodipodi:role="line"
id="tspan4572"
x="28.533201"
y="155.87793">0.3</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="60.875481"
id="text4574"><tspan
sodipodi:role="line"
id="tspan4576"
x="28.533201"
y="60.875481">0.8</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="79.87793"
id="text4578"><tspan
sodipodi:role="line"
id="tspan4580"
x="28.533201"
y="79.87793">0.7</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.162107"
y="22.87793"
id="text4582"><tspan
sodipodi:role="line"
id="tspan4584"
x="28.162107"
y="22.87793">1.0</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.533201"
y="41.875492"
id="text4586"><tspan
sodipodi:role="line"
id="tspan4588"
x="28.533201"
y="41.875492">0.9</tspan></text>
<text
xml:space="preserve"
style="font-size:10px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="28.939205"
y="212.87793"
id="text4590"><tspan
sodipodi:role="line"
id="tspan4592"
x="28.939205"
y="212.87793">0.0</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="195.05258"
y="247.85966"
id="text4604"
transform="scale(1.0000012,0.9999988)"><tspan
sodipodi:role="line"
id="tspan4606"
x="195.05258"
y="247.85966">Abstraction</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:center;writing-mode:lr-tb;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial;"
x="-126.09961"
y="10.589844"
id="text4608"
transform="matrix(0,-1,1,0,0,0)"><tspan
sodipodi:role="line"
id="tspan4610"
x="-126.09961"
y="10.589844">Instability</tspan></text>
<text
xml:space="preserve"
style="font-size:9px;font-style:normal;font-weight:normal;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L"
x="313.30417"
y="246.10596"
id="text2692"><tspan
sodipodi:role="line"
id="tspan2694"
x="313.30417"
y="246.10596"
style="font-size:9px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;fill:#2e3436;font-family:Arial; Italic">Generated by PDepend</tspan></text>
<ellipse
sodipodi:ry="15"
sodipodi:rx="15"
sodipodi:cy="15"
sodipodi:cx="15"
id="jdepend.bad"
xml:id="jdepend.bad"
style="fill:url(#jdepend.bad.gradient);stroke:none"
ry="15"
rx="15"
cy="15"
cx="15"
transform="translate(163,4)" />
<ellipse
sodipodi:ry="15"
sodipodi:rx="15"
sodipodi:cy="15"
sodipodi:cx="15"
id="jdepend.good"
xml:id="jdepend.good"
style="fill:url(#jdepend.good.gradient);stroke:none"
ry="15"
rx="15"
cy="15"
cx="15"
transform="matrix(0.6,0,0,0.6,41,10)" />
</g>
<g>
<text
xml:space="preserve"
style="font-size:4px;font-family:Arial;fill:#2e3436;"
x="195.05258"
y="120.85966"
xml:id="jdepend.legend">Package</text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 23 KiB

@@ -0,0 +1,65 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report;
use LogicException;
/**
* This type of exception is thrown, if a required log target/log file wasn't
* configured for the current logger instance.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class NoLogOutputException extends LogicException
{
/**
* Creates a new log target exception for the given log instance.
*/
public function __construct(ReportGenerator $logger)
{
$className = get_class($logger);
parent::__construct("The log target is not configured for '$className'.");
}
}
@@ -0,0 +1,340 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report\Overview;
use DOMDocument;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\Analyzer\CouplingAnalyzer;
use PDepend\Metrics\Analyzer\CyclomaticComplexityAnalyzer;
use PDepend\Metrics\Analyzer\InheritanceAnalyzer;
use PDepend\Metrics\Analyzer\NodeCountAnalyzer;
use PDepend\Metrics\Analyzer\NodeLocAnalyzer;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Util\FileUtil;
use PDepend\Util\ImageConvert;
use RuntimeException;
/**
* This logger generates a system overview pyramid, as described in the book
* <b>Object-Oriented Metrics in Practice</b>.
*
* http://www.springer.com/computer/programming/book/978-3-540-24429-5
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Pyramid implements FileAwareGenerator
{
/**
* The output file name.
*
* @var string
*/
private $logFile = null;
/**
* The used coupling analyzer.
*
* @var CouplingAnalyzer
*/
private $coupling = null;
/**
* The used cyclomatic complexity analyzer.
*
* @var CyclomaticComplexityAnalyzer
*/
private $cyclomaticComplexity = null;
/**
* The used inheritance analyzer.
*
* @var InheritanceAnalyzer
*/
private $inheritance = null;
/**
* The used node count analyzer.
*
* @var NodeCountAnalyzer
*/
private $nodeCount = null;
/**
* The used node loc analyzer.
*
* @var NodeLocAnalyzer
*/
private $nodeLoc = null;
/**
* Holds defined thresholds for the computed proportions. This set is based
* on java thresholds, we should find better values for php projects.
*
* @var array<string, array<int, float>>
*/
private $thresholds = array(
'cyclo-loc' => array(0.16, 0.20, 0.24),
'loc-nom' => array(7, 10, 13),
'nom-noc' => array(4, 7, 10),
'noc-nop' => array(6, 17, 26),
'calls-nom' => array(2.01, 2.62, 3.2),
'fanout-calls' => array(0.56, 0.62, 0.68),
'andc' => array(0.25, 0.41, 0.57),
'ahh' => array(0.09, 0.21, 0.32)
);
/**
* Sets the output log file.
*
* @param string $logFile The output log file.
*
* @return void
*/
public function setLogFile($logFile)
{
$this->logFile = $logFile;
}
/**
* Returns an <b>array</b> with accepted analyzer types. These types can be
* concrete analyzer classes or one of the descriptive analyzer interfaces.
*
* @return array<string>
*/
public function getAcceptedAnalyzers()
{
return array(
'pdepend.analyzer.coupling',
'pdepend.analyzer.cyclomatic_complexity',
'pdepend.analyzer.inheritance',
'pdepend.analyzer.node_count',
'pdepend.analyzer.node_loc',
);
}
/**
* Adds an analyzer to log. If this logger accepts the given analyzer it
* with return <b>true</b>, otherwise the return value is <b>false</b>.
*
* @param Analyzer $analyzer The analyzer to log.
*
* @return bool
*/
public function log(Analyzer $analyzer)
{
if ($analyzer instanceof CyclomaticComplexityAnalyzer) {
$this->cyclomaticComplexity = $analyzer;
} elseif ($analyzer instanceof CouplingAnalyzer) {
$this->coupling = $analyzer;
} elseif ($analyzer instanceof InheritanceAnalyzer) {
$this->inheritance = $analyzer;
} elseif ($analyzer instanceof NodeCountAnalyzer) {
$this->nodeCount = $analyzer;
} elseif ($analyzer instanceof NodeLocAnalyzer) {
$this->nodeLoc = $analyzer;
} else {
return false;
}
return true;
}
/**
* Closes the logger process and writes the output file.
*
* @throws NoLogOutputException
*
* @return void
*/
public function close()
{
// Check for configured log file
if ($this->logFile === null) {
throw new NoLogOutputException($this);
}
$metrics = $this->collectMetrics();
$proportions = $this->computeProportions($metrics);
$svg = new DOMDocument('1.0', 'UTF-8');
$svg->loadXML(file_get_contents(dirname(__FILE__) . '/pyramid.svg'));
$items = array_merge($metrics, $proportions);
foreach ($items as $name => $value) {
$svg->getElementById("pdepend.{$name}")->nodeValue = $value;
if (($threshold = $this->computeThreshold($name, $value)) === null) {
continue;
}
if (($color = $svg->getElementById("threshold.{$threshold}")) === null) {
continue;
}
if (($rect = $svg->getElementById("rect.{$name}")) === null) {
continue;
}
preg_match('/fill:(#[^;"]+)/', $color->getAttribute('style'), $match);
$style = $rect->getAttribute('style');
$style = preg_replace('/fill:#[^;"]+/', "fill:{$match[1]}", $style);
$rect->setAttribute('style', $style);
}
$temp = FileUtil::getSysTempDir();
$temp .= '/' . uniqid('pdepend_') . '.svg';
$svg->save($temp);
ImageConvert::convert($temp, $this->logFile);
// Remove temp file
unlink($temp);
}
/**
* Computes the threshold (low, average, high) for the given value and metric.
* If no threshold is defined for the given name, this method will return
* <b>null</b>.
*
* @param string $name The metric/field identfier.
* @param mixed $value The metric/field value.
*
* @return string|null
*/
private function computeThreshold($name, $value)
{
if (!isset($this->thresholds[$name])) {
return null;
}
$threshold = $this->thresholds[$name];
if ($value <= $threshold[0]) {
return 'low';
} elseif ($value >= $threshold[2]) {
return 'high';
} else {
$low = $value - $threshold[0];
$avg = $threshold[1] - $value;
if ($low < $avg) {
return 'low';
}
}
return 'average';
}
/**
* Computes the proportions between the given metrics.
*
* @param array<string, float> $metrics The aggregated project metrics.
*
* @return array<string, float>
*/
private function computeProportions(array $metrics)
{
$orders = array(
array('cyclo', 'loc', 'nom', 'noc', 'nop'),
array('fanout', 'calls', 'nom')
);
$proportions = array();
foreach ($orders as $names) {
for ($i = 1, $c = count($names); $i < $c; ++$i) {
$value1 = $metrics[$names[$i]];
$value2 = $metrics[$names[$i - 1]];
$identifier = "{$names[$i - 1]}-{$names[$i]}";
$proportions[$identifier] = 0;
if ($value1 > 0) {
$proportions[$identifier] = round($value2 / $value1, 3);
}
}
}
return $proportions;
}
/**
* Aggregates the required metrics from the registered analyzers.
*
* @throws RuntimeException If one of the required analyzers isn't set.
*
* @return array<string, mixed>
*/
private function collectMetrics()
{
if ($this->coupling === null) {
throw new RuntimeException('Missing Coupling analyzer.');
}
if ($this->cyclomaticComplexity === null) {
throw new RuntimeException('Missing Cyclomatic Complexity analyzer.');
}
if ($this->inheritance === null) {
throw new RuntimeException('Missing Inheritance analyzer.');
}
if ($this->nodeCount === null) {
throw new RuntimeException('Missing Node Count analyzer.');
}
if ($this->nodeLoc === null) {
throw new RuntimeException('Missing Node LOC analyzer.');
}
$coupling = $this->coupling->getProjectMetrics();
$cyclomatic = $this->cyclomaticComplexity->getProjectMetrics();
$inheritance = $this->inheritance->getProjectMetrics();
$nodeCount = $this->nodeCount->getProjectMetrics();
$nodeLoc = $this->nodeLoc->getProjectMetrics();
return array(
'cyclo' => $cyclomatic['ccn2'],
'loc' => $nodeLoc['eloc'],
'nom' => ($nodeCount['nom'] + $nodeCount['nof']),
'noc' => $nodeCount['noc'],
'nop' => $nodeCount['nop'],
'ahh' => round($inheritance['ahh'], 3),
'andc' => round($inheritance['andc'], 3),
'fanout' => $coupling['fanout'],
'calls' => $coupling['calls']
);
}
}
@@ -0,0 +1,769 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="390"
height="250"
id="svg5110"
sodipodi:version="0.32"
inkscape:version="0.46"
version="1.0"
sodipodi:docname="pyramid.svg"
inkscape:output_extension="org.inkscape.output.svg.inkscape">
<defs
id="defs5112">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 526.18109 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="744.09448 : 526.18109 : 1"
inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
id="perspective5118" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
gridtolerance="10000"
guidetolerance="10"
objecttolerance="10"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="1.5"
inkscape:cx="179.96345"
inkscape:cy="96.137457"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="1280"
inkscape:window-height="753"
inkscape:window-x="0"
inkscape:window-y="46" />
<metadata
id="metadata5115">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<rect
style="fill:#555753"
width="0"
height="0"
x="0"
y="0"
rx="0"
ry="0"
id="rect8982"
xml:id="threshold.low" />
<rect
style="fill:#73d216"
width="0"
height="0"
x="0"
y="0"
rx="0"
ry="0"
id="rect8983"
xml:id="threshold.average" />
<rect
style="fill:#f57900"
width="0"
height="0"
x="0"
y="0"
rx="0"
ry="0"
id="rect2834"
xml:id="threshold.high" />
<rect
style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4954"
width="118.69567"
height="16.956522"
x="232.7668"
y="185.67191"
rx="2.9780269"
ry="0" />
<rect
style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4956"
width="157.2332"
height="34"
x="232.7668"
y="201"
rx="3.9449191"
ry="0" />
<rect
style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4958"
width="80.158104"
height="33.913044"
x="154.15019"
y="122.47035"
rx="2.0111351"
ry="0" />
<rect
style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4960"
width="234.30832"
height="34"
x="0"
y="201"
rx="5.8787031"
ry="0" />
<rect
style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4962"
width="195.77077"
height="16.956522"
x="38.537552"
y="185.67191"
rx="4.9118109"
ry="0" />
<rect
style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4964"
width="157.2332"
height="16.956522"
x="77.075104"
y="170.25687"
rx="3.9449191"
ry="0" />
<rect
style="opacity:1;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4966"
width="118.69567"
height="16.956522"
x="115.61267"
y="154.84189"
rx="2.9780269"
ry="0" />
<rect
style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4968"
width="231.22531"
height="30.83004"
x="1.541504"
y="202.62846"
rx="5.8013515"
ry="0" />
<rect
style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4970"
width="192.68774"
height="15.41502"
x="40.079056"
y="187.21365"
rx="4.8344593"
ry="0" />
<rect
style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4972"
width="154.15019"
height="15.41502"
x="78.616608"
y="171.79837"
rx="3.8675678"
ry="0" />
<rect
style="opacity:1;fill:#d3d7cf;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4974"
width="115.61266"
height="15.41502"
x="117.15414"
y="156.38339"
rx="2.9006755"
ry="0" />
<rect
style="opacity:1;fill:#fcaf3e;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4976"
width="77.075096"
height="30.83004"
x="155.6917"
y="124.01187"
rx="1.9337839"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4978"
width="154.15019"
height="30.83004"
x="234.3083"
y="202.62846"
rx="3.8675678"
ry="0" />
<rect
style="opacity:1;fill:#babdb6;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4980"
width="115.61266"
height="15.41502"
x="234.3083"
y="187.21341"
rx="2.9006755"
ry="0" />
<rect
style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4982"
xml:id="rect.andc"
width="38.537548"
height="15.43004"
x="194.22925"
y="124.01187"
rx="0.96689194"
ry="0" />
<rect
style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect2851"
xml:id="rect.ahh"
width="38.537548"
height="15.4"
x="194.22925"
y="139.41187"
rx="0.96689194"
ry="0" />
<rect
style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4984"
xml:id="rect.noc-nop"
width="38.537548"
height="15.41502"
x="117.15414"
y="156.38339"
rx="0.80574334" />
<rect
style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4986"
xml:id="rect.nom-noc"
width="38.537548"
height="15.41502"
x="78.616608"
y="171.79837"
rx="0.80574334" />
<rect
style="opacity:1;fill:#73d216;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4988"
xml:id="rect.loc-nom"
width="38.537548"
height="15.41502"
x="40.079056"
y="187.21341"
rx="0.80574334" />
<rect
style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4990"
xml:id="rect.cyclo-loc"
width="38.537548"
height="15.41502"
x="1.541504"
y="202.62846"
rx="0.80574334" />
<rect
style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4992"
xml:id="rect.calls-nom"
width="38.537548"
height="15.41502"
x="311.38339"
y="187.21341"
rx="0.80574334" />
<rect
style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4994"
xml:id="rect.fanout-calls"
width="38.537548"
height="15.41502"
x="349.92096"
y="202.62846"
rx="0.80574334" />
<rect
style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4996"
width="231.22531"
height="1"
x="1.541504"
y="217.04344"
rx="5.8013515"
ry="0" />
<rect
style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect4998"
width="192.68774"
height="1"
x="40.079056"
y="201.62846"
rx="4.8344593"
ry="0" />
<rect
style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5000"
width="154.15019"
height="1"
x="78.616608"
y="186.21341"
rx="3.8675678"
ry="0" />
<rect
style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5002"
width="115.61266"
height="1"
x="117.15414"
y="170.79837"
rx="2.9006755"
ry="0" />
<rect
style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5004"
width="115.61266"
height="1"
x="234.3083"
y="201.62846"
rx="2.9006755"
ry="0" />
<rect
style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5006"
width="154.15019"
height="1"
x="234.3083"
y="217.04344"
rx="3.8675678"
ry="0" />
<rect
style="opacity:1;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="rect5008"
width="77.075096"
height="1"
x="155.6917"
y="138.42685"
rx="1.9337839"
ry="0" />
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="158"
y="135"
title="Average Number of Derived Classes"
id="text5010"><tspan
sodipodi:role="line"
title="Average Number of Derived Classes"
id="tspan5012"
x="158"
y="135">ANDC</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="158"
y="151"
title="Average Hierarchy Height"
id="text5014"><tspan
sodipodi:role="line"
title="Average Hierarchy Height"
id="tspan5016"
x="158"
y="151">AHH</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="158"
y="168"
title="Number Of Packages"
id="text5018"><tspan
sodipodi:role="line"
title="Number Of Packages"
id="tspan5020"
x="158"
y="168">NOP</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="119"
y="183.00002"
id="text5022"
title="Number Of Classes"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number Of Classes"
id="tspan5024"
x="119"
y="183.00002">NOC</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="81"
y="198.00002"
id="text5026"
title="Number Of Methods (Methods+Functions)"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number Of Methods (Methods+Functions)"
id="tspan5028"
x="81"
y="198.00002">NOM</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="42"
y="213.00002"
id="text5030"
title="Lines Of Code (Non Comment and Non Whitespace Lines)"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Lines Of Code (Non Comment and Non Whitespace Lines)"
id="tspan5032"
x="42"
y="213.00002">LOC</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="3"
y="230.00002"
id="text5034"
title="Cyclomatic Complexity"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Cyclomatic Complexity"
id="tspan5036"
x="3"
y="230.00002">CYCLO</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:end;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="308.85785"
y="198.00043"
id="text5038"
title="Number Of Methods (Methods+Functions)"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number Of Methods (Methods+Functions)"
id="tspan5040"
x="308.85785"
y="198.00043">NOM</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="348"
y="213.00002"
id="text5042"
title="Number of Operation Calls"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number of Operation Calls"
id="tspan5044"
x="348"
y="213.00002">CALLS</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="387"
y="230.00002"
id="text5046"
title="Number of Called Classes"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number of Called Classes"
id="tspan5048"
x="387"
y="230.00002">FANOUT</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Number of Called Classes"
x="236"
y="230.00002"
id="text5050"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number of Called Classes"
id="tspan5052"
xml:id="pdepend.fanout"
x="236"
y="230.00002">8590</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Number of Operation Calls"
x="236"
y="213.00002"
id="text5054"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number of Operation Calls"
id="tspan5056"
xml:id="pdepend.calls"
x="236"
y="213.00002">15128</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Cyclomatic Complexity"
x="232"
y="230.00002"
id="text5058"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Cyclomatic Complexity"
id="tspan5060"
xml:id="pdepend.cyclo"
x="232"
y="230.00002">5579</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Lines Of Code (Non Comment and Non Whitespace Lines)"
x="232"
y="213.00002"
id="text5062"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
xml:id="pdepend.loc"
title="Lines Of Code (Non Comment and Non Whitespace Lines)"
id="tspan5064"
x="232"
y="213.00002">35175</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Number Of Methods (Methods+Functions)"
x="232"
y="198.00002"
id="text5066"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number Of Methods (Methods+Functions)"
id="tspan5068"
xml:id="pdepend.nom"
x="232"
y="198.00002">3618</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Number Of Packages"
x="232"
y="168.00002"
id="text5070"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number Of Packages"
id="tspan5072"
xml:id="pdepend.nop"
x="232"
y="168.00002">19</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Number Of Classes"
x="232"
y="183.00002"
id="text5074"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Number Of Classes"
id="tspan5076"
xml:id="pdepend.noc"
x="232"
y="183.00002">384</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Average Number of Derived Classes"
x="232"
y="135.00002"
id="text5078"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Average Number of Derived Classes"
id="tspan5080"
xml:id="pdepend.andc"
x="232"
y="135.00002">0,31</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Average Hierarchy Height"
x="232"
y="151.00002"
id="text5082"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Average Hierarchy Height"
id="tspan5084"
xml:id="pdepend.ahh"
x="232"
y="151.00002">0,12</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Ratio: Number of Classes / Number of Packages"
x="119"
y="168.00002"
id="text5086"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Ratio: Number of Classes / Number of Packages"
id="tspan5088"
xml:id="pdepend.noc-nop"
x="119"
y="168.00002">20,21</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Ratio: Number of Methods / Number of Classes"
x="81"
y="183.00002"
id="text5090"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Ratio: Number of Methods / Number of Classes"
id="tspan5092"
xml:id="pdepend.nom-noc"
x="81"
y="183.00002">9,42</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Ratio: Lines of Code / Number of Methods"
x="42"
y="198.00002"
id="text5094"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Ratio: Lines of Code / Number of Methods"
id="tspan5096"
xml:id="pdepend.loc-nom"
x="42"
y="198.00002">9,72</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Ratio: Cyclomatic Complexity / Lines of Code"
x="3"
y="213.00002"
id="text5098"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Ratio: Cyclomatic Complexity / Lines of Code"
id="tspan5100"
xml:id="pdepend.cyclo-loc"
x="3"
y="213.00002">0,15</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Ratio: Number of Called Classes(FANOUT) / Number of Operation Calls"
x="388.56299"
y="213.00002"
id="text5102"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Ratio: Number of Called Classes(FANOUT) / Number of Operation Calls"
id="tspan5104"
xml:id="pdepend.fanout-calls"
x="388.56299"
y="213.00002">0,561</tspan></text>
<text
xml:space="preserve"
style="font-size:11px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-anchor:end;fill:#eeeeec;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
title="Ratio: Number of Operation Calls / Number of Methods (Methods+Functions)"
x="348"
y="198.00002"
id="text5106"
transform="scale(0.9999985,1.0000015)"><tspan
sodipodi:role="line"
title="Ratio: Number of Operation Calls / Number of Methods (Methods+Functions)"
id="tspan5108"
xml:id="pdepend.calls-nom"
x="348"
y="198.00002">4,18</tspan></text>
<text
xml:space="preserve"
style="font-size:8px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:end;text-anchor:end;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:Arial"
x="386.39493"
y="246.10596"
id="text2692"><tspan
sodipodi:role="line"
id="tspan2694"
x="386.39493"
y="246.10596"
style="font-size:9px;font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:end;text-anchor:end;fill:#2e3436;font-family:Arial;">Generated by PDepend</tspan></text>
<path
sodipodi:type="arc"
style="opacity:1;fill:#555753;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3780"
sodipodi:cx="53.333332"
sodipodi:cy="285.66666"
sodipodi:rx="12"
sodipodi:ry="10.333333"
d="M 65.333332,285.66666 A 12,10.333333 0 1 1 41.333332,285.66666 A 12,10.333333 0 1 1 65.333332,285.66666 z"
transform="matrix(0.375,0,0,0.4354839,-5.4999995,119.09677)" />
<text
xml:space="preserve"
style="font-size:8px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L;"
x="32.386719"
y="246.64209"
id="text3782"><tspan
sodipodi:role="line"
id="tspan3784"
x="32.386719"
y="246.64209"
style="font-size:9px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#2e3436;font-family:Arial;">Low</tspan></text>
<path
sodipodi:type="arc"
style="opacity:1;fill:#73d216;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3786"
sodipodi:cx="53.333332"
sodipodi:cy="285.66666"
sodipodi:rx="12"
sodipodi:ry="10.333333"
d="M 65.333332,285.66666 A 12,10.333333 0 1 1 41.333332,285.66666 A 12,10.333333 0 1 1 65.333332,285.66666 z"
transform="matrix(0.375,0,0,0.4354839,54.5,119.09677)" />
<text
xml:space="preserve"
style="font-size:8px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L;"
x="102.38672"
y="245.77417"
id="text3788"><tspan
sodipodi:role="line"
id="tspan3790"
x="102.38672"
y="245.77417"
style="font-size:9px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#2e3436;font-family:Arial;">Average</tspan></text>
<path
sodipodi:type="arc"
style="opacity:1;fill:#f57900;fill-opacity:1;stroke:none;stroke-width:1;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3792"
sodipodi:cx="53.333332"
sodipodi:cy="285.66666"
sodipodi:rx="12"
sodipodi:ry="10.333333"
d="M 65.333332,285.66666 A 12,10.333333 0 1 1 41.333332,285.66666 A 12,10.333333 0 1 1 65.333332,285.66666 z"
transform="matrix(0.375,0,0,0.4354839,132.5,119.09677)" />
<text
xml:space="preserve"
style="font-size:8px;font-style:normal;font-weight:bold;text-align:center;text-anchor:middle;fill:#2e3436;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;font-family:URW Chancery L;"
x="170.38672"
y="245.77417"
id="text3794"><tspan
sodipodi:role="line"
id="tspan3796"
x="170.38672"
y="245.77417"
style="font-size:9px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;fill:#2e3436;font-family:Arial;">High</tspan></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 30 KiB

@@ -0,0 +1,81 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report;
use PDepend\Metrics\Analyzer;
/**
* Base interface for all PDepend report generators.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface ReportGenerator
{
/**
* Adds an analyzer to log. If this logger accepts the given analyzer it
* with return <b>true</b>, otherwise the return value is <b>false</b>.
*
* @param Analyzer $analyzer The analyzer to log.
*
* @return bool
*/
public function log(Analyzer $analyzer);
/**
* Closes the logger process and writes the output file.
*
* @throws NoLogOutputException If the no log target exists.
*
* @return void
*/
public function close();
/**
* Returns an <b>array</b> with accepted analyzer types. These types can be
* concrete analyzer classes or one of the descriptive analyzer interfaces.
*
* @return array<string>
*/
public function getAcceptedAnalyzers();
}
@@ -0,0 +1,125 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report;
use RuntimeException;
use Symfony\Component\DependencyInjection\TaggedContainerInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* This factory creates singleton instances of available loggers.
*
* The identifiers are used to find a matching service in the DIC
* that is tagged with 'pdepend.logger' and has an option attribute
* named after the identifier, prefixed with --:
*
* Identifier "my-custom-logger" searchs for:
*
* <tag name="pdepend.logger" option="--my-custom-logger" />
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ReportGeneratorFactory
{
/**
* @var TaggedContainerInterface
*/
private $container;
/**
* @param TaggedContainerInterface $container
*/
public function __construct(ContainerInterface $container)
{
$this->container = $container;
}
/**
* Creates a new generator or returns an existing instance for the given
* <b>$identifier</b>.
*
* @param string $identifier The generator identifier.
* @param string $fileName The log output file name.
*
* @throws RuntimeException
*
* @return ReportGenerator
*/
public function createGenerator($identifier, $fileName)
{
if (!isset($this->instances[$identifier])) {
$loggerServices = $this->container->findTaggedServiceIds('pdepend.logger');
$logger = null;
foreach ($loggerServices as $id => $loggerServiceTags) {
foreach ($loggerServiceTags as $loggerServiceTag) {
if ($loggerServiceTag['option'] === '--' . $identifier) {
$logger = $this->container->get($id);
}
}
}
if (!$logger) {
throw new RuntimeException(sprintf('Unknown generator with identifier "%s".', $identifier));
}
// TODO: Refactor this into an external log configurator or a similar
// concept.
if ($logger instanceof FileAwareGenerator) {
$logger->setLogFile($fileName);
}
$this->instances[$identifier] = $logger;
}
return $this->instances[$identifier];
}
/**
* Set of created logger instances.
*
* @var ReportGenerator[]
*/
protected $instances = array();
}
@@ -0,0 +1,464 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Report\Summary;
use DOMDocument;
use DOMElement;
use PDepend\Metrics\Analyzer;
use PDepend\Metrics\AnalyzerNodeAware;
use PDepend\Metrics\AnalyzerProjectAware;
use PDepend\Report\CodeAwareGenerator;
use PDepend\Report\FileAwareGenerator;
use PDepend\Report\NoLogOutputException;
use PDepend\Source\AST\AbstractASTArtifact;
use PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTClass;
use PDepend\Source\AST\ASTCompilationUnit;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTInterface;
use PDepend\Source\AST\ASTMethod;
use PDepend\Source\AST\ASTNamespace;
use PDepend\Source\AST\ASTTrait;
use PDepend\Source\ASTVisitor\AbstractASTVisitor;
use PDepend\Util\Utf8Util;
/**
* This logger generates a summary xml document with aggregated project, class,
* method and file metrics.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class Xml extends AbstractASTVisitor implements CodeAwareGenerator, FileAwareGenerator
{
/**
* The log output file.
*
* @var string
*/
private $logFile = null;
/**
* The raw {@link ASTNamespace} instances.
*
* @var ASTArtifactList<ASTNamespace>
*/
protected $code = null;
/**
* Set of all analyzed files.
*
* @var ASTCompilationUnit[]
*/
protected $fileSet = array();
/**
* List of all analyzers that implement the node aware interface
* {@link AnalyzerNodeAware}.
*
* @var AnalyzerNodeAware[]
*/
private $nodeAwareAnalyzers = array();
/**
* List of all analyzers that implement the node aware interface
* {@link AnalyzerProjectAware}.
*
* @var AnalyzerProjectAware[]
*/
private $projectAwareAnalyzers = array();
/**
* The internal used xml stack.
*
* @var DOMElement[]
*/
private $xmlStack = array();
/**
* Sets the output log file.
*
* @param string $logFile The output log file.
*
* @return void
*/
public function setLogFile($logFile)
{
$this->logFile = $logFile;
}
/**
* Returns an <b>array</b> with accepted analyzer types. These types can be
* concrete analyzer classes or one of the descriptive analyzer interfaces.
*
* @return array<string>
*/
public function getAcceptedAnalyzers()
{
return array(
'pdepend.analyzer.cyclomatic_complexity',
'pdepend.analyzer.node_loc',
'pdepend.analyzer.npath_complexity',
'pdepend.analyzer.inheritance',
'pdepend.analyzer.node_count',
'pdepend.analyzer.hierarchy',
'pdepend.analyzer.crap_index',
'pdepend.analyzer.code_rank',
'pdepend.analyzer.coupling',
'pdepend.analyzer.class_level',
'pdepend.analyzer.cohesion',
'pdepend.analyzer.halstead',
'pdepend.analyzer.maintainability',
);
}
/**
* Sets the context code nodes.
*
* @param ASTArtifactList<ASTNamespace> $artifacts
*
* @return void
*/
public function setArtifacts(ASTArtifactList $artifacts)
{
$this->code = $artifacts;
}
/**
* Adds an analyzer to log. If this logger accepts the given analyzer it
* with return <b>true</b>, otherwise the return value is <b>false</b>.
*
* @param Analyzer $analyzer The analyzer to log.
*
* @return bool
*/
public function log(Analyzer $analyzer)
{
$accepted = false;
if ($analyzer instanceof AnalyzerProjectAware) {
$this->projectAwareAnalyzers[] = $analyzer;
$accepted = true;
}
if ($analyzer instanceof AnalyzerNodeAware) {
$this->nodeAwareAnalyzers[] = $analyzer;
$accepted = true;
}
return $accepted;
}
/**
* Closes the logger process and writes the output file.
*
* @throws NoLogOutputException If the no log target exists.
*
* @return void
*/
public function close()
{
if ($this->logFile === null) {
throw new NoLogOutputException($this);
}
$dom = new DOMDocument('1.0', 'UTF-8');
$dom->formatOutput = true;
$metrics = $dom->createElement('metrics');
$metrics->setAttribute('generated', date('Y-m-d\TH:i:s'));
$metrics->setAttribute('pdepend', '@package_version@');
foreach ($this->getProjectMetrics() as $name => $value) {
$metrics->setAttribute($name, $value);
}
array_push($this->xmlStack, $metrics);
foreach ($this->code as $node) {
$node->accept($this);
}
if (count($this->fileSet) > 0) {
$filesXml = $dom->createElement('files');
foreach ($this->fileSet as $file) {
$fileXml = $dom->createElement('file');
$fileXml->setAttribute('name', Utf8Util::ensureEncoding($file->getFileName()));
$this->writeNodeMetrics($fileXml, $file);
$filesXml->appendChild($fileXml);
}
$metrics->insertBefore($filesXml, $metrics->firstChild);
}
$dom->appendChild($metrics);
$buffer = $dom->saveXML();
file_put_contents($this->logFile, $buffer);
}
/**
* Returns an array with all collected project metrics.
*
* @return array<string, mixed>
*
* @since 0.9.10
*/
private function getProjectMetrics()
{
$projectMetrics = array();
foreach ($this->projectAwareAnalyzers as $analyzer) {
$projectMetrics = array_merge(
$projectMetrics,
$analyzer->getProjectMetrics()
);
}
ksort($projectMetrics);
return $projectMetrics;
}
/**
* Visits a class node.
*
* @return void
*/
public function visitClass(ASTClass $class)
{
$this->generateTypeXml($class, 'class');
}
/**
* Visits a trait node.
*
* @return void
*/
public function visitTrait(ASTTrait $trait)
{
$this->generateTypeXml($trait, 'trait');
}
/**
* Generates the XML for a class or trait node.
*
* @param string $typeIdentifier
*
* @return void
*/
private function generateTypeXml(ASTClass $type, $typeIdentifier)
{
if (!$type->isUserDefined()) {
return;
}
$xml = end($this->xmlStack);
if (!$xml) {
return;
}
$doc = $xml->ownerDocument;
$typeXml = $doc->createElement($typeIdentifier);
$typeXml->setAttribute('name', Utf8Util::ensureEncoding($type->getName()));
$typeXml->setAttribute('fqname', Utf8Util::ensureEncoding($type->getNamespacedName()));
$typeXml->setAttribute('start', (string)$type->getStartLine());
$typeXml->setAttribute('end', (string)$type->getEndLine());
$this->writeNodeMetrics($typeXml, $type);
$this->writeFileReference($typeXml, $type->getCompilationUnit());
$xml->appendChild($typeXml);
array_push($this->xmlStack, $typeXml);
foreach ($type->getMethods() as $method) {
$method->accept($this);
}
foreach ($type->getProperties() as $property) {
$property->accept($this);
}
array_pop($this->xmlStack);
}
/**
* Visits a function node.
*
* @return void
*/
public function visitFunction(ASTFunction $function)
{
$xml = end($this->xmlStack);
if (!$xml) {
return;
}
$doc = $xml->ownerDocument;
$functionXml = $doc->createElement('function');
$functionXml->setAttribute('name', Utf8Util::ensureEncoding($function->getName()));
$functionXml->setAttribute('start', (string)$function->getStartLine());
$functionXml->setAttribute('end', (string)$function->getEndLine());
$this->writeNodeMetrics($functionXml, $function);
$this->writeFileReference($functionXml, $function->getCompilationUnit());
$xml->appendChild($functionXml);
}
/**
* Visits a code interface object.
*
* @return void
*/
public function visitInterface(ASTInterface $interface)
{
// Empty implementation, because we don't want interface methods.
}
/**
* Visits a method node.
*
* @return void
*/
public function visitMethod(ASTMethod $method)
{
$xml = end($this->xmlStack);
if (!$xml) {
return;
}
$doc = $xml->ownerDocument;
$methodXml = $doc->createElement('method');
$methodXml->setAttribute('name', Utf8Util::ensureEncoding($method->getName()));
$methodXml->setAttribute('start', (string)$method->getStartLine());
$methodXml->setAttribute('end', (string)$method->getEndLine());
$this->writeNodeMetrics($methodXml, $method);
$xml->appendChild($methodXml);
}
/**
* Visits a namespace node.
*
* @return void
*/
public function visitNamespace(ASTNamespace $namespace)
{
$xml = end($this->xmlStack);
if (!$xml) {
return;
}
$doc = $xml->ownerDocument;
$packageXml = $doc->createElement('package');
$packageXml->setAttribute('name', Utf8Util::ensureEncoding($namespace->getName()));
$this->writeNodeMetrics($packageXml, $namespace);
array_push($this->xmlStack, $packageXml);
foreach ($namespace->getTypes() as $type) {
$type->accept($this);
}
foreach ($namespace->getFunctions() as $function) {
$function->accept($this);
}
array_pop($this->xmlStack);
if ($packageXml->firstChild === null) {
return;
}
$xml->appendChild($packageXml);
}
/**
* Aggregates all metrics for the given <b>$node</b> instance and adds them
* to the <b>\DOMElement</b>
*
* @return void
*/
protected function writeNodeMetrics(DOMElement $xml, AbstractASTArtifact $node)
{
$metrics = array();
foreach ($this->nodeAwareAnalyzers as $analyzer) {
$metrics = array_merge($metrics, $analyzer->getNodeMetrics($node));
}
foreach ($metrics as $name => $value) {
$xml->setAttribute($name, $value);
}
}
/**
* Appends a file reference element to the given <b>$xml</b> element.
*
* <code>
* <class name="\PDepend\Engine">
* <file name="PDepend/Engine.php" />
* </class>
* </code>
*
* @param DOMElement $xml The parent xml element.
* @param ASTCompilationUnit $compilationUnit The code file instance.
*
* @return void
*/
protected function writeFileReference(DOMElement $xml, ASTCompilationUnit $compilationUnit = null)
{
if (in_array($compilationUnit, $this->fileSet, true) === false) {
$this->fileSet[] = $compilationUnit;
}
$fileXml = $xml->ownerDocument->createElement('file');
$fileXml->setAttribute('name', Utf8Util::ensureEncoding($compilationUnit->getFileName()));
$xml->appendChild($fileXml);
}
}
@@ -0,0 +1,72 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.6
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* An instance of this class represents an object allocation.
*
* <code>
* function foo()
* {
* // -------------
* new bar\Baz();
* // -------------
*
* // ---------
* new Foo();
* // ---------
* }
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.6
*/
class ASTAllocationExpression extends AbstractASTNode
{
}
@@ -0,0 +1,332 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 2.3
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* Represents a php class node.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 2.3
*/
class ASTAnonymousClass extends ASTClass implements ASTNode
{
/**
* The parent node of this node or <b>null</b> when this node is the root
* of a node tree.
*
* @var ASTNode|null
*/
protected $parent = null;
/**
* Metadata for this node instance, serialized in a string. This string
* contains the start, end line, and the start, end column and the node
* image in a colon separated string.
*
* @var string
*
* @since 0.10.4
*/
protected $metadata = ':::';
/**
* @param string $image
*
* @return void
*/
public function setImage($image)
{
$this->setName($image);
}
/**
* Returns the source image of this ast node.
*
* @return string
*/
public function getImage()
{
return $this->getName();
}
/**
* Returns the start line for this ast node.
*
* @return int
*/
public function getStartLine()
{
return $this->getMetadataInteger(0);
}
/**
* Returns the start column for this ast node.
*
* @return int
*/
public function getStartColumn()
{
return $this->getMetadataInteger(2);
}
/**
* Returns the end line for this ast node.
*
* @return int
*/
public function getEndLine()
{
return $this->getMetadataInteger(1);
}
/**
* Returns the end column for this ast node.
*
* @return int
*/
public function getEndColumn()
{
return $this->getMetadataInteger(3);
}
/**
* For better performance we have moved the single setter methods for the
* node columns and lines into this configure method.
*
* @param int $startLine
* @param int $endLine
* @param int $startColumn
* @param int $endColumn
*
* @return void
*
* @since 0.9.10
*/
public function configureLinesAndColumns($startLine, $endLine, $startColumn, $endColumn)
{
$this->setMetadataInteger(0, $startLine);
$this->setMetadataInteger(1, $endLine);
$this->setMetadataInteger(2, $startColumn);
$this->setMetadataInteger(3, $endColumn);
}
/**
* Returns the parent node of this node or <b>null</b> when this node is
* the root of a node tree.
*
* @return ASTNode
*/
public function getParent()
{
return $this->parent;
}
/**
* Sets the parent node of this node.
*
* @return void
*/
public function setParent(ASTNode $node)
{
$this->parent = $node;
}
/**
* Traverses up the node tree and finds all parent nodes that are instances
* of <b>$parentType</b>.
*
* @param string $parentType
*
* @return ASTNode[]
*/
public function getParentsOfType($parentType)
{
$parents = array();
$parentNode = $this->parent;
while (is_object($parentNode)) {
if ($parentNode instanceof $parentType) {
array_unshift($parents, $parentNode);
}
$parentNode = $parentNode->getParent();
}
return $parents;
}
/**
* This method adds a new child node at the first position of the children.
*
* @return void
*/
public function prependChild(ASTNode $node)
{
array_unshift($this->nodes, $node);
$node->setParent($this);
}
/**
* Will return <b>true</b> if this class was declared anonymous in an
* allocation expression.
*
* @return bool
*/
public function isAnonymous()
{
return true;
}
/**
* The magic sleep method will be called by PHP's runtime environment right
* before an instance of this class gets serialized. It should return an
* array with those property names that should be serialized for this class.
*
* @return array
*
* @since 0.10.0
*/
public function __sleep()
{
return array_merge(array('metadata'), parent::__sleep());
}
/**
* The magic wakeup method will be called by PHP's runtime environment when
* a serialized instance of this class was unserialized. This implementation
* of the wakeup method will register this object in the the global class
* context.
*
* @return void
*/
public function __wakeup()
{
$this->methods = null;
foreach ($this->nodes as $node) {
$node->setParent($this);
}
parent::__wakeup();
}
/**
* Returns an integer value that was stored under the given index.
*
* @param int $index
*
* @return int
*
* @since 0.10.4
*/
protected function getMetadataInteger($index)
{
return (int) $this->getMetadata($index);
}
/**
* Stores an integer value under the given index in the internally used data
* string.
*
* @param int $index
* @param int $value
*
* @return void
*
* @since 0.10.4
*/
protected function setMetadataInteger($index, $value)
{
$this->setMetadata($index, (string)$value);
}
/**
* Returns the value that was stored under the given index.
*
* @param int $index
*
* @return string
*
* @since 0.10.4
*/
protected function getMetadata($index)
{
$metadata = explode(':', $this->metadata, $this->getMetadataSize());
return $metadata[$index];
}
/**
* Stores the given value under the given index in an internal storage
* container.
*
* @param int $index
* @param string $value
*
* @return void
*
* @since 0.10.4
*/
protected function setMetadata($index, $value)
{
$metadata = explode(':', $this->metadata, $this->getMetadataSize());
$metadata[$index] = $value;
$this->metadata = join(':', $metadata);
}
/**
* Returns the total number of the used property bag.
*
* @return int
*
* @since 0.10.4
*/
protected function getMetadataSize()
{
return 4;
}
}
@@ -0,0 +1,117 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.6
*/
namespace PDepend\Source\AST;
use InvalidArgumentException;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This class represents arguments as they are supplied to functions or
* constructors invocations.
*
* <code>
* // ------------
* Foo::bar($x, $y, $z);
* // ------------
*
* // ------------
* $foo->bar($x, $y, $z);
* // ------------
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.6
*/
class ASTArguments extends AbstractASTNode
{
/**
* This method will return true if the argument list is declared as foo(...)
*
* @return bool
*
* @since 2.11.0
*/
public function isVariadicPlaceholder()
{
return $this->getMetadataBoolean(4);
}
/**
* This method can be used to mark the argument list as variadic placeholder
*
* @return void
* @since 2.11.0
*/
public function setVariadicPlaceholder()
{
$this->setMetadataBoolean(4, true);
}
/**
* Rather the given arguments list can still take one more argument.
*
* @return bool
*/
public function acceptsMoreArguments()
{
return true;
}
/**
* This method adds a new child node to this node instance.
*
* @return void
*/
public function addChild(ASTNode $node)
{
if (!$this->acceptsMoreArguments()) {
throw new InvalidArgumentException('No more arguments allowed.');
}
parent::addChild($node);
}
}
@@ -0,0 +1,69 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This class represents an array expression.
*
* <code>
* // -------------------------------------
* $array = array( 1, 2, 3, array( $a, $b, $c ) );
* // -------------------------------------
*
* // ---------------------------
* $array = [ 1, 2, 3, [ $a, $b, $c ] ];
* // ---------------------------
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
class ASTArray extends ASTExpression
{
}
@@ -0,0 +1,102 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This class represents a single array element expression.
*
* <code>
* // _ ______ __________________________
* // __ ___ __________
* $array = array( 1, 2 => 3, array( $a, &$b, 1 => &$c ) );
*
* // _ ______ _____________________
* // __ ___ ________
* $array = [ 1, 2 => 3, [ $a, &$b, 1 => &$c ] ];
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
class ASTArrayElement extends ASTExpression
{
/**
* This method will return <b>true</b> when the element value is passed by
* reference.
*
* @return bool
*/
public function isByReference()
{
return $this->getMetadataBoolean(5);
}
/**
* This method can be used to mark the element value as passed by reference.
*
* @return void
*/
public function setByReference()
{
$this->setMetadataBoolean(5, true);
}
/**
* Returns the total number of the used property bag.
*
* @return int
*
* @since 0.10.4
* @see ASTNode#getMetadataSize()
*/
protected function getMetadataSize()
{
return 6;
}
}
@@ -0,0 +1,69 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a array-expression.
*
* <code>
* ------
* $x[42];
* ------
*
* -----------
* $this->foo[23][42];
* -----------
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
class ASTArrayIndexExpression extends ASTIndexExpression
{
}
@@ -0,0 +1,81 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* Abstract base class for code item.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface ASTArtifact /* extends ASTNode */
{
/**
* Returns the artifact name.
*
* @return string
*
* @deprecated Use getImage() inherit from ASTNode class.
*/
public function getName();
/**
* Returns a id for this code node.
*
* @return string
*/
public function getId();
/**
* ASTVisitor method for node tree traversal.
*
* @template T of array<string, mixed>|string|null
*
* @param T $data
*
* @return T
*/
public function accept(ASTVisitor $visitor, $data = null);
}
@@ -0,0 +1,258 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
use ArrayAccess;
use BadMethodCallException;
use Countable;
use Iterator;
use OutOfBoundsException;
use PDepend\Source\AST\ASTArtifactList\CollectionArtifactFilter;
use ReturnTypeWillChange;
/**
* Iterator for code nodes.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @template T of ASTArtifact
* @implements \Iterator<int|string, T>
* @implements \ArrayAccess<int|string, T>
*/
class ASTArtifactList implements ArrayAccess, Iterator, Countable
{
/**
* List of {@link ASTArtifact} objects in
* this iterator.
*
* @var T[]
*/
private $artifacts = array();
/**
* Total number of available nodes.
*
* @var int
*/
private $count = 0;
/**
* Current internal offset.
*
* @var int
*/
private $offset = 0;
/**
* Constructs a new node iterator from the given {@link ASTArtifact}
* node array.
*
* @param T[] $artifacts
*/
public function __construct(array $artifacts)
{
$filter = CollectionArtifactFilter::getInstance();
$nodeKeys = array();
foreach ($artifacts as $artifact) {
$id = $artifact->getId();
if (isset($nodeKeys[$id])) {
continue;
}
if ($filter->accept($artifact)) {
$nodeKeys[$id] = $id;
$this->artifacts[] = $artifact;
++$this->count;
}
}
}
/**
* Returns the number of {@link ASTArtifact}
* objects in this iterator.
*
* @return int
*/
#[ReturnTypeWillChange]
public function count()
{
return count($this->artifacts);
}
/**
* Returns the current node or <b>false</b>
*
* @return false|T
*/
#[ReturnTypeWillChange]
public function current()
{
if ($this->offset >= $this->count) {
return false;
}
return $this->artifacts[$this->offset];
}
/**
* Returns the name of the current {@link ASTArtifact}.
*
* @return string
*/
#[ReturnTypeWillChange]
public function key()
{
return $this->artifacts[$this->offset]->getName();
}
/**
* Moves the internal pointer to the next {@link ASTArtifact}.
*
* @return void
*/
#[ReturnTypeWillChange]
public function next()
{
++$this->offset;
}
/**
* Rewinds the internal pointer.
*
* @return void
*/
#[ReturnTypeWillChange]
public function rewind()
{
$this->offset = 0;
}
/**
* Returns <b>true</b> while there is a next {@link ASTArtifact}.
*
* @return bool
*/
#[ReturnTypeWillChange]
public function valid()
{
return ($this->offset < $this->count);
}
/**
* Whether a offset exists
*
* @param mixed $offset An offset to check for.
*
* @return bool Returns true on success or false on failure. The return
* value will be casted to boolean if non-boolean was returned.
*
* @since 1.0.0
* @link http://php.net/manual/en/arrayaccess.offsetexists.php
*/
#[ReturnTypeWillChange]
public function offsetExists($offset)
{
return isset($this->artifacts[$offset]);
}
/**
* Offset to retrieve
*
* @param mixed $offset
*
* @throws OutOfBoundsException
*
* @return T Can return all value types.
*
* @since 1.0.0
* @link http://php.net/manual/en/arrayaccess.offsetget.php
*/
#[ReturnTypeWillChange]
public function offsetGet($offset)
{
if (isset($this->artifacts[$offset])) {
return $this->artifacts[$offset];
}
throw new OutOfBoundsException("The offset {$offset} does not exist.");
}
/**
* Offset to set
*
* @param mixed $offset
* @param mixed $value
*
* @throws BadMethodCallException
*
* @return void
*
* @since 1.0.0
* @link http://php.net/manual/en/arrayaccess.offsetset.php
*/
#[ReturnTypeWillChange]
public function offsetSet($offset, $value)
{
throw new BadMethodCallException('Not supported operation.');
}
/**
* Offset to unset
*
* @param mixed $offset
*
* @throws BadMethodCallException
*
* @return void
*
* @since 1.0.0
* @link http://php.net/manual/en/arrayaccess.offsetunset.php
*/
#[ReturnTypeWillChange]
public function offsetUnset($offset)
{
throw new BadMethodCallException('Not supported operation.');
}
}
@@ -0,0 +1,62 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTArtifact;
/**
* Base interface for {@link ASTArtifactList} filters.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface ArtifactFilter
{
/**
* Returns <b>true</b> if the given node should be part of the node iterator,
* otherwise this method will return <b>false</b>.
*
* @return bool
*/
public function accept(ASTArtifact $node);
}
@@ -0,0 +1,121 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTArtifact;
/**
* Static composite filter for code nodes. This class is used for an overall
* filtering.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @fixme Never ever use a singleton!!!
*/
final class CollectionArtifactFilter implements ArtifactFilter
{
/**
* Singleton instance of this filter.
*
* @var CollectionArtifactFilter
*/
private static $instance = null;
/**
* Singleton method for this filter class.
*
* @return CollectionArtifactFilter
*/
public static function getInstance()
{
if (self::$instance === null) {
self::$instance = new CollectionArtifactFilter();
}
return self::$instance;
}
/**
* Constructs a new static filter.
*
* @access private
*/
public function __construct()
{
}
/**
* An optional configured filter instance.
*
* @var ArtifactFilter
*/
private $filter = null;
/**
* Sets the used filter instance.
*
* @param ArtifactFilter $filter
*
* @return void
*
* @since 0.9.12
*/
public function setFilter(ArtifactFilter $filter = null)
{
$this->filter = $filter;
}
/**
* Returns <b>true</b> if the given node should be part of the node iterator,
* otherwise this method will return <b>false</b>.
*
* @return bool
*/
public function accept(ASTArtifact $node)
{
if ($this->filter === null) {
return true;
}
return $this->filter->accept($node);
}
}
@@ -0,0 +1,65 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\ASTArtifact;
/**
* This is a simple NULL-implementation of the code filter interface.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class NullArtifactFilter implements ArtifactFilter
{
/**
* Returns <b>true</b> if the given node should be part of the node iterator,
* otherwise this method will return <b>false</b>.
*
* @return bool
*/
public function accept(ASTArtifact $node)
{
return true;
}
}
@@ -0,0 +1,101 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST\ASTArtifactList;
use PDepend\Source\AST\AbstractASTClassOrInterface;
use PDepend\Source\AST\ASTArtifact;
use PDepend\Source\AST\ASTFunction;
use PDepend\Source\AST\ASTNamespace;
/**
* This class implements a filter that is based on the namespace.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class PackageArtifactFilter implements ArtifactFilter
{
/**
* Regexp with ignorable namespace names and namespace name fragments.
*
* @var string
*/
private $pattern = '';
/**
* Constructs a new namespace filter for the given list of namespace names.
*
* @param array<string> $namespaces
*/
public function __construct(array $namespaces)
{
$patterns = array();
foreach ($namespaces as $namespace) {
$patterns[] = str_replace('\*', '\S*', preg_quote($namespace));
}
$this->pattern = '#^(' . join('|', $patterns) . ')$#D';
}
/**
* Returns <b>true</b> if the given node should be part of the node iterator,
* otherwise this method will return <b>false</b>.
*
* @return bool
*/
public function accept(ASTArtifact $node)
{
$namespace = null;
// NOTE: This looks a little bit ugly and it seems better to exclude
// ASTMethod and ASTProperty, but when PDepend supports more node
// types, this could produce errors.
if ($node instanceof AbstractASTClassOrInterface) {
$namespace = $node->getNamespace()->getName();
} elseif ($node instanceof ASTFunction) {
$namespace = $node->getNamespace()->getName();
} elseif ($node instanceof ASTNamespace) {
$namespace = $node->getName();
}
return (preg_match($this->pattern, $namespace) === 0);
}
}
@@ -0,0 +1,55 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents any kind of assignment.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ASTAssignmentExpression extends AbstractASTNode
{
}
@@ -0,0 +1,59 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.8
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a boolean and-expression.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.8
*/
class ASTBooleanAndExpression extends AbstractASTNode
{
}
@@ -0,0 +1,59 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.8
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a boolean or-expression.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.8
*/
class ASTBooleanOrExpression extends AbstractASTNode
{
}
@@ -0,0 +1,73 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a break-statement.
*
* <code>
* ------
* break;
* ------
*
* ---------
* break 42;
* ---------
*
* ----------------------
* break $this->foobar();
* ----------------------
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
class ASTBreakStatement extends ASTStatement
{
}
@@ -0,0 +1,57 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
/**
* Base interface for all callables.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
interface ASTCallable
{
/**
* @return ASTType
*/
public function getReturnType();
}
@@ -0,0 +1,171 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.15
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This class represents a cast-expression node.
*
* <code>
* // ----------
* $foo = (int) $bar;
* // ----------
*
* // -----------
* $foo = (bool) $bar;
* // -----------
*
* // ------------
* $foo = (array) $bar;
* // ------------
*
* // ------------
* $foo = (unset) $bar;
* // ------------
*
* // -------------
* $foo = (double) $bar;
* // -------------
*
* // -------------
* $foo = (string) $bar;
* // -------------
*
* // -------------
* $foo = (object) $bar;
* // -------------
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.15
*/
class ASTCastExpression extends ASTUnaryExpression
{
/**
* Constructs a new cast-expression node.
*
* @param string $image The original cast image.
*/
public function __construct($image)
{
parent::__construct(preg_replace('(\s+)', '', strtolower($image)));
}
/**
* Returns <b>true</b> when this node represents an array cast-expression.
*
* @return bool
*/
public function isArray()
{
return ($this->getImage() === '(array)');
}
/**
* Returns <b>true</b> when this node represents an object cast-expression.
*
* @return bool
*/
public function isObject()
{
return ($this->getImage() === '(object)');
}
/**
* Returns <b>true</b> when this node represents a boolean cast-expression.
*
* @return bool
*/
public function isBoolean()
{
return ($this->getImage() === '(bool)' || $this->getImage() === '(boolean)');
}
/**
* Returns <b>true</b> when this node represents an integer cast-expression.
*
* @return bool
*/
public function isInteger()
{
return ($this->getImage() === '(int)' || $this->getImage() === '(integer)');
}
/**
* Returns <b>true</b> when this node represents a float cast-expression.
*
* @return bool
*/
public function isFloat()
{
return ($this->getImage() === '(real)'
|| $this->getImage() === '(float)'
|| $this->getImage() === '(double)'
);
}
/**
* Returns <b>true</b> when this node represents a string cast-expression.
*
* @return bool
*/
public function isString()
{
return (strcmp('(string)', $this->getImage()) === 0);
}
/**
* Returns <b>true</b> when this node represents an unset cast-expression.
*
* @return bool
*/
public function isUnset()
{
return ($this->getImage() === '(unset)');
}
}
@@ -0,0 +1,55 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a catch-statement.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ASTCatchStatement extends ASTStatement
{
}
@@ -0,0 +1,221 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
use BadMethodCallException;
use InvalidArgumentException;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* Represents a php class node.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ASTClass extends AbstractASTClassOrInterface
{
/**
* List of associated properties.
*
* @var ASTProperty[]
*/
private $properties = null;
/**
* Returns <b>true</b> if this is an abstract class or an interface.
*
* @return bool
*/
public function isAbstract()
{
return (($this->modifiers & State::IS_EXPLICIT_ABSTRACT) === State::IS_EXPLICIT_ABSTRACT);
}
/**
* This method will return <b>true</b> when this class is declared as final.
*
* @return bool
*/
public function isFinal()
{
return (($this->modifiers & State::IS_FINAL) === State::IS_FINAL);
}
/**
* This method will return <b>true</b> when this class is declared as readonly.
*
* @return bool
*/
public function isReadonly()
{
return (($this->modifiers & State::IS_READONLY) === State::IS_READONLY);
}
/**
* Will return <b>true</b> if this class was declared anonymous in an
* allocation expression.
*
* @return bool
*/
public function isAnonymous()
{
return false;
}
/**
* Returns all properties for this class.
*
* @return ASTArtifactList<ASTProperty>
*/
public function getProperties()
{
if ($this->properties === null) {
$this->properties = array();
$declarations = $this->findChildrenOfType('PDepend\\Source\\AST\\ASTFieldDeclaration');
foreach ($declarations as $declaration) {
$declarators = $declaration->findChildrenOfType('PDepend\\Source\\AST\\ASTVariableDeclarator');
foreach ($declarators as $declarator) {
$property = new ASTProperty($declaration, $declarator);
$property->setDeclaringClass($this);
$property->setCompilationUnit($this->getCompilationUnit());
$this->properties[] = $property;
}
}
}
return new ASTArtifactList($this->properties);
}
/**
* Checks that this user type is a subtype of the given <b>$type</b> instance.
*
* @return bool
*/
public function isSubtypeOf(AbstractASTType $type)
{
if ($type === $this) {
return true;
} elseif ($type instanceof ASTInterface) {
foreach ($this->getInterfaces() as $interface) {
if ($interface === $type) {
return true;
}
}
} elseif (($parent = $this->getParentClass()) !== null) {
if ($parent === $type) {
return true;
}
return $parent->isSubtypeOf($type);
}
return false;
}
/**
* Returns the declared modifiers for this type.
*
* @return int
*
* @since 0.9.4
*/
public function getModifiers()
{
return $this->modifiers;
}
/**
* This method sets a OR combined integer of the declared modifiers for this
* node.
*
* This method will throw an exception when the value of given <b>$modifiers</b>
* contains an invalid/unexpected modifier
*
* @param int $modifiers
*
* @throws BadMethodCallException
* @throws InvalidArgumentException
*
* @return void
*
* @since 0.9.4
*/
public function setModifiers($modifiers)
{
if ($this->modifiers !== 0) {
throw new BadMethodCallException(
'Cannot overwrite previously set class modifiers.'
);
}
$expected = ~State::IS_EXPLICIT_ABSTRACT
& ~State::IS_IMPLICIT_ABSTRACT
& ~State::IS_FINAL
& ~State::IS_READONLY;
if (($expected & $modifiers) !== 0) {
throw new InvalidArgumentException('Invalid class modifier given.');
}
$this->modifiers = $modifiers;
}
/**
* The magic wakeup method will be called by PHP's runtime environment when
* a serialized instance of this class was unserialized. This implementation
* of the wakeup method will register this object in the the global class
* context.
*
* @return void
*
* @since 0.10.0
*/
public function __wakeup()
{
parent::__wakeup();
$this->context->registerClass($this);
}
}
@@ -0,0 +1,69 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 2.0.0
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This class represents the full qualified class name postfix.
*
* <code>
* // -----
* Foo::class
* // -----
*
* // -----
* $bar:: class;
* // -----
* </code>
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 2.0.0
*/
class ASTClassFqnPostfix extends AbstractASTNode
{
}
@@ -0,0 +1,73 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
namespace PDepend\Source\AST;
use RuntimeException;
/**
* This type of exception will be thrown when an inheritance hierarchy is
* recursive, so that .
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 1.0.0
*/
class ASTClassOrInterfaceRecursiveInheritanceException extends RuntimeException
{
/**
* Constructs a new exception instance.
*/
public function __construct(AbstractASTClassOrInterface $type)
{
parent::__construct(
sprintf(
'Type %s\%s is part of an endless inheritance hierarchy.',
preg_replace('(\W+)', '\\', $type->getNamespace()->getName()),
$type->getName()
)
);
}
}
@@ -0,0 +1,114 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.5
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Source\Builder\BuilderContext;
/**
* This class is used as a placeholder for unknown classes or interfaces. It
* will resolve the concrete type instance on demand.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.5
*/
class ASTClassOrInterfaceReference extends ASTType
{
/**
* The global AST builder context.
*
* @var BuilderContext
*/
protected $context = null;
/**
* An already loaded type instance.
*
* @var AbstractASTClassOrInterface|null
*/
protected $typeInstance = null;
/**
* Constructs a new type holder instance.
*
* @param string $qualifiedName
*/
public function __construct(BuilderContext $context, $qualifiedName)
{
parent::__construct($qualifiedName);
$this->context = $context;
}
/**
* Returns the concrete type instance associated with with this placeholder.
*
* @return AbstractASTClassOrInterface
*/
public function getType()
{
if ($this->typeInstance === null) {
$this->typeInstance = $this->context->getClassOrInterface(
$this->getImage()
);
}
return $this->typeInstance;
}
/**
* Magic method which returns the names of all those properties that should
* be cached for this node instance.
*
* @return array
*
* @since 0.10.0
*/
public function __sleep()
{
return array_merge(array('context'), parent::__sleep());
}
}
@@ -0,0 +1,91 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
/**
* This is a special implementation of the node iterator that will translate
* a list of given {@link ASTClassOrInterfaceReference} holders
* into a list of unique {@link AbstractASTClassOrInterface}
* instances.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @extends ASTArtifactList<AbstractASTClassOrInterface>
*/
class ASTClassOrInterfaceReferenceIterator extends ASTArtifactList
{
/**
* Constructs a new reference iterator instance.
*
* @param ASTClassOrInterfaceReference[] $references List of references to concrete type instances.
*/
public function __construct(array $references)
{
parent::__construct($this->createClassesAndInterfaces($references));
}
/**
* This method creates a set of {@link AbstractASTClassOrInterface}
* objects from the given reference array.
*
* @param ASTClassOrInterfaceReference[] $references
*
* @return AbstractASTClassOrInterface[]
*/
protected function createClassesAndInterfaces(array $references)
{
$classesAndInterfaces = array();
foreach ($references as $reference) {
$classOrInterface = $reference->getType();
if (isset($classesAndInterfaces[$classOrInterface->getId()])) {
continue;
}
$classesAndInterfaces[$classOrInterface->getId()] = $classOrInterface;
}
return $classesAndInterfaces;
}
}
@@ -0,0 +1,72 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.5
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This is a classes only version of the class or interface reference .
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.5
*/
class ASTClassReference extends ASTClassOrInterfaceReference
{
/**
* Returns the concrete type instance associated with with this placeholder.
*
* @return ASTClass
*/
public function getType()
{
if (!$this->typeInstance instanceof ASTClass) {
$this->typeInstance = $this->context->getClass($this->getImage());
}
return $this->typeInstance;
}
}
@@ -0,0 +1,59 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a clone-expression.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
class ASTCloneExpression extends ASTExpression
{
}
@@ -0,0 +1,150 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a closure-expression.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.9.12
*/
class ASTClosure extends AbstractASTNode implements ASTCallable
{
/**
* @return ASTType|null
*/
public function getReturnType()
{
foreach ($this->nodes as $node) {
if ($node instanceof ASTType) {
return $node;
}
}
return null;
}
/**
* This method will return <b>true</b> when this closure returns by
* reference.
*
* @return bool
*/
public function returnsByReference()
{
return $this->getMetadataBoolean(5);
}
/**
* This method can be used to flag this closure as returns by reference.
*
* @param bool $returnsReference Does this closure return by reference?
*
* @return void
*/
public function setReturnsByReference($returnsReference)
{
$this->setMetadataBoolean(5, (boolean) $returnsReference);
}
/**
* Returns whether this closure was defined as static or not.
*
* This method will return <b>TRUE</b> when the closure was declared as
* followed:
*
* <code>
* $closure = static function( $e ) {
* return pow( $e, 2 );
* }
* </code>
*
* And it will return <b>FALSE</b> when we declare the closure as usual:
*
* <code>
* $closure = function( $e ) {
* return pow( $e, 2 );
* }
* </code>
*
* @return bool
*
* @since 1.0.0
*/
public function isStatic()
{
return $this->getMetadataBoolean(6);
}
/**
* This method can be used to flag this closure instance as static.
*
* @param bool $static Whether this closure is static or not.
*
* @return void
*
* @since 1.0.0
*/
public function setStatic($static)
{
$this->setMetadataBoolean(6, (boolean) $static);
}
/**
* Returns the total number of the used property bag.
*
* @return int
*
* @since 1.0.0
* @see ASTNode#getMetadataSize()
*/
protected function getMetadataSize()
{
return 7;
}
}
@@ -0,0 +1,55 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
use PDepend\Source\ASTVisitor\ASTVisitor;
/**
* This node class represents a comment.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ASTComment extends AbstractASTNode
{
}
@@ -0,0 +1,392 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
namespace PDepend\Source\AST;
use InvalidArgumentException;
use PDepend\Source\ASTVisitor\ASTVisitor;
use PDepend\Source\Tokenizer\Token;
use PDepend\Util\Cache\CacheDriver;
/**
* This class provides an interface to a single source file.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*/
class ASTCompilationUnit extends AbstractASTArtifact
{
/**
* The internal used cache instance.
*
* @var CacheDriver|null
*
* @since 0.10.0
*/
protected $cache = null;
/**
* The unique identifier for this function.
*
* @var string|null
*/
protected $id = null;
/**
* The source file name/path.
*
* @var string|null
*/
protected $fileName = null;
/**
* The comment for this type.
*
* @var string|null
*/
protected $comment = null;
/**
* The files start line. This property must always have the value <em>1</em>.
*
* @var int
*
* @since 0.10.0
*/
protected $startLine = 0;
/**
* The files end line.
*
* @var int
*
* @since 0.10.0
*/
protected $endLine = 0;
/**
* List of classes, interfaces and functions that parsed from this file.
*
* @var AbstractASTArtifact[]
*
* @since 0.10.0
*/
protected $childNodes = array();
/**
* Was this file instance restored from the cache?
*
* @var bool
*
* @since 0.10.0
*/
protected $cached = false;
/**
* Normalized code in this file.
*
* @var string|null
*/
private $source = null;
/**
* Constructs a new source file instance.
*
* @param string|null $fileName The source file name/path.
*/
public function __construct($fileName)
{
if ($fileName && strpos($fileName, 'php://') === 0) {
$this->fileName = $fileName;
} elseif ($fileName !== null) {
$this->fileName = realpath($fileName) ?: null;
}
}
/**
* Returns the physical file name for this object.
*
* @return string|null
*/
public function getName()
{
return $this->fileName;
}
/**
* Returns the physical file name for this object.
*
* @return string|null
*/
public function getFileName()
{
return $this->fileName;
}
/**
* Returns a id for this code node.
*
* @return string|null
*/
public function getId()
{
return $this->id;
}
/**
* Sets the unique identifier for this file instance.
*
* @param string $id Identifier for this file.
*
* @return void
*
* @since 0.9.12
*/
public function setId($id)
{
$this->id = $id;
}
/**
* Setter method for the used parser and token cache.
*
* @return $this
*
* @since 0.10.0
*/
public function setCache(CacheDriver $cache)
{
$this->cache = $cache;
return $this;
}
/**
* Returns normalized source code with stripped whitespaces.
*
* @return string|null
*/
public function getSource()
{
$this->readSource();
return $this->source;
}
/**
* Returns an <b>array</b> with all tokens within this file.
*
* @return array<Token>
*/
public function getTokens()
{
return (array) $this->cache
->type('tokens')
->restore($this->getId());
}
/**
* Sets the tokens for this file.
*
* @param array<Token> $tokens The generated tokens.
*
* @return void
*/
public function setTokens(array $tokens)
{
$this->cache
->type('tokens')
->store($this->getId(), $tokens);
}
/**
* Adds a source item that was parsed from this source file.
*
* @return void
*
* @since 0.10.0
*/
public function addChild(AbstractASTArtifact $artifact)
{
$this->childNodes[$artifact->getId()] = $artifact;
}
/**
* Returns the start line number for this source file. For an existing file
* this value must always be <em>1</em>, while it can be <em>0</em> for a
* not existing dummy file.
*
* @return int
*
* @since 0.10.0
*/
public function getStartLine()
{
if ($this->startLine === 0) {
$this->readSource();
}
return $this->startLine;
}
/**
* Returns the start line number for this source file. For an existing file
* this value must always be greater <em>0</em>, while it can be <em>0</em>
* for a not existing dummy file.
*
* @return int
*
* @since 0.10.0
*/
public function getEndLine()
{
if ($this->endLine === 0) {
$this->readSource();
}
return $this->endLine;
}
/**
* This method will return <b>true</b> when this file instance was restored
* from the cache and not currently parsed. Otherwise this method will return
* <b>false</b>.
*
* @return bool
*
* @since 0.10.0
*/
public function isCached()
{
return $this->cached;
}
/**
* The magic sleep method will be called by PHP's runtime environment right
* before it serializes an instance of this class. This method returns an
* array with those property names that should be serialized.
*
* @return array<string>
*
* @since 0.10.0
*/
public function __sleep()
{
return array(
'cache',
'childNodes',
'comment',
'endLine',
'fileName',
'startLine',
'id'
);
}
/**
* The magic wakeup method will is called by PHP's runtime environment when
* a serialized instance of this class was unserialized. This implementation
* of the wakeup method restores the references between all parsed entities
* in this source file and this file instance.
*
* @return void
*
* @since 0.10.0
* @see ASTCompilationUnit::$childNodes
*/
public function __wakeup()
{
$this->cached = true;
foreach ($this->childNodes as $childNode) {
$childNode->setCompilationUnit($this);
}
}
/**
* Returns the string representation of this class.
*
* @return string
*/
public function __toString()
{
return ($this->fileName === null ? '' : $this->fileName);
}
/**
* Reads the source file if required.
*
* @return void
*/
protected function readSource()
{
if (
$this->source === null &&
$this->fileName &&
(strpos($this->fileName, 'php://') === 0 || file_exists($this->fileName))
) {
$source = file_get_contents($this->fileName);
$this->source = str_replace(array("\r\n", "\r"), "\n", $source);
$this->startLine = 1;
$this->endLine = substr_count($this->source, "\n") + 1;
}
}
// Deprecated methods
// @codeCoverageIgnoreStart
/**
* This method can be called by the PDepend runtime environment or a
* utilizing component to free up memory. This methods are required for
* PHP version < 5.3 where cyclic references can not be resolved
* automatically by PHP's garbage collector.
*
* @return void
*
* @since 0.9.12
* @deprecated Since 0.10.0
*/
public function free()
{
fwrite(STDERR, __METHOD__ . ' is deprecated since version 0.10.0' . PHP_EOL);
}
// @codeCoverageIgnoreEnd
}
@@ -0,0 +1,73 @@
<?php
/**
* This file is part of PDepend.
*
* PHP Version 5
*
* Copyright (c) 2008-2017 Manuel Pichler <mapi@pdepend.org>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Manuel Pichler nor the names of his
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.10.0
*/
namespace PDepend\Source\AST;
use RuntimeException;
/**
* This type of exception will be thrown when the source file of a code object
* is accessed, but this property is not available.
*
* @copyright 2008-2017 Manuel Pichler. All rights reserved.
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
*
* @since 0.10.0
*/
class ASTCompilationUnitNotFoundException extends RuntimeException
{
/**
* Constructs a new exception instance.
*/
public function __construct(AbstractASTArtifact $owner)
{
parent::__construct(
sprintf(
'The mandatory parent was not defined for the %s named %s.',
get_class($owner),
$owner->getName()
)
);
}
}
Loaded 100 of 11877 files, more files were not shown because too many files have changed in this diff. Show more