@@ -68,6 +68,11 @@ class PHP_CodeCoverage
6868 */
6969 private $ filter ;
7070
71+ /**
72+ * @var PHP_CodeCoverage_Parser
73+ */
74+ private $ parser ;
75+
7176 /**
7277 * @var boolean
7378 */
@@ -110,11 +115,6 @@ class PHP_CodeCoverage
110115 */
111116 private $ data = array ();
112117
113- /**
114- * @var array
115- */
116- private $ ignoredLines = array ();
117-
118118 /**
119119 * Test data.
120120 *
@@ -131,24 +131,27 @@ class PHP_CodeCoverage
131131 */
132132 public function __construct (PHP_CodeCoverage_Driver $ driver = null , PHP_CodeCoverage_Filter $ filter = null )
133133 {
134+ if ($ filter === null ) {
135+ $ filter = new PHP_CodeCoverage_Filter ;
136+ }
137+
138+ $ parser = new PHP_CodeCoverage_Parser ;
139+
134140 if ($ driver === null ) {
135141 $ runtime = new Runtime ;
136142
137143 if ($ runtime ->isHHVM ()) {
138- $ driver = new PHP_CodeCoverage_Driver_HHVM ;
144+ $ driver = new PHP_CodeCoverage_Driver_HHVM ( $ filter , $ parser ) ;
139145 } elseif ($ runtime ->hasXdebug ()) {
140- $ driver = new PHP_CodeCoverage_Driver_Xdebug ;
146+ $ driver = new PHP_CodeCoverage_Driver_Xdebug ( $ filter , $ parser ) ;
141147 } else {
142148 throw new PHP_CodeCoverage_Exception ('No code coverage driver available ' );
143149 }
144150 }
145151
146- if ($ filter === null ) {
147- $ filter = new PHP_CodeCoverage_Filter ;
148- }
149-
150152 $ this ->driver = $ driver ;
151153 $ this ->filter = $ filter ;
154+ $ this ->parser = $ parser ;
152155 }
153156
154157 /**
@@ -197,12 +200,6 @@ public function getData()
197200 $ this ->addUncoveredFilesFromWhitelist ();
198201 }
199202
200- // We need to apply the blacklist filter a second time
201- // when no whitelist is used.
202- if (!$ this ->filter ->hasWhitelist ()) {
203- $ this ->applyListsFilter ($ this ->data );
204- }
205-
206203 return $ this ->data ;
207204 }
208205
@@ -317,8 +314,6 @@ public function append(array $data, $id = null, $append = true, $linesToBeCovere
317314 throw new PHP_CodeCoverage_Exception ;
318315 }
319316
320- $ this ->applyListsFilter ($ data );
321- $ this ->applyIgnoredLinesFilter ($ data );
322317 $ this ->initializeFilesThatAreSeenTheFirstTime ($ data );
323318
324319 if (!$ append ) {
@@ -407,6 +402,8 @@ public function setCacheTokens($flag)
407402 );
408403 }
409404
405+ $ this ->parser ->setCacheTokens ($ flag );
406+
410407 $ this ->cacheTokens = $ flag ;
411408 }
412409
@@ -540,42 +537,6 @@ private function applyCoversAnnotationFilter(array &$data, $linesToBeCovered, ar
540537 }
541538 }
542539
543- /**
544- * Applies the blacklist/whitelist filtering.
545- *
546- * @param array $data
547- */
548- private function applyListsFilter (array &$ data )
549- {
550- foreach (array_keys ($ data ) as $ filename ) {
551- if ($ this ->filter ->isFiltered ($ filename )) {
552- unset($ data [$ filename ]);
553- }
554- }
555- }
556-
557- /**
558- * Applies the "ignored lines" filtering.
559- *
560- * @param array $data
561- */
562- private function applyIgnoredLinesFilter (array &$ data )
563- {
564- foreach (array_keys ($ data ) as $ filename ) {
565- if (!$ this ->filter ->isFile ($ filename )) {
566- continue ;
567- }
568-
569- foreach ($ this ->getLinesToBeIgnored ($ filename ) as $ line ) {
570- unset($ data [$ filename ][$ line ]);
571- }
572-
573- if (empty ($ data [$ filename ])) {
574- unset($ data [$ filename ]);
575- }
576- }
577- }
578-
579540 /**
580541 * @param array $data
581542 * @since Method available since Release 1.1.0
@@ -654,171 +615,6 @@ private function processUncoveredFileFromWhitelist($uncoveredFile, array &$data,
654615 }
655616 }
656617
657- /**
658- * Returns the lines of a source file that should be ignored.
659- *
660- * @param string $filename
661- * @return array
662- * @throws PHP_CodeCoverage_Exception
663- * @since Method available since Release 2.0.0
664- */
665- private function getLinesToBeIgnored ($ filename )
666- {
667- if (!is_string ($ filename )) {
668- throw PHP_CodeCoverage_Util_InvalidArgumentHelper::factory (
669- 1 ,
670- 'string '
671- );
672- }
673-
674- if (!isset ($ this ->ignoredLines [$ filename ])) {
675- $ this ->ignoredLines [$ filename ] = array ();
676- $ ignore = false ;
677- $ stop = false ;
678- $ lines = file ($ filename );
679- $ numLines = count ($ lines );
680-
681- foreach ($ lines as $ index => $ line ) {
682- if (!trim ($ line )) {
683- $ this ->ignoredLines [$ filename ][] = $ index + 1 ;
684- }
685- }
686-
687- if ($ this ->cacheTokens ) {
688- $ tokens = PHP_Token_Stream_CachingFactory::get ($ filename );
689- } else {
690- $ tokens = new PHP_Token_Stream ($ filename );
691- }
692-
693- $ classes = array_merge ($ tokens ->getClasses (), $ tokens ->getTraits ());
694- $ tokens = $ tokens ->tokens ();
695-
696- foreach ($ tokens as $ token ) {
697- switch (get_class ($ token )) {
698- case 'PHP_Token_COMMENT ' :
699- case 'PHP_Token_DOC_COMMENT ' :
700- $ _token = trim ($ token );
701- $ _line = trim ($ lines [$ token ->getLine () - 1 ]);
702-
703- if ($ _token == '// @codeCoverageIgnore ' ||
704- $ _token == '//@codeCoverageIgnore ' ) {
705- $ ignore = true ;
706- $ stop = true ;
707- } elseif ($ _token == '// @codeCoverageIgnoreStart ' ||
708- $ _token == '//@codeCoverageIgnoreStart ' ) {
709- $ ignore = true ;
710- } elseif ($ _token == '// @codeCoverageIgnoreEnd ' ||
711- $ _token == '//@codeCoverageIgnoreEnd ' ) {
712- $ stop = true ;
713- }
714-
715- // Do not ignore the whole line when there is a token
716- // before the comment on the same line
717- if (0 === strpos ($ _token , $ _line )) {
718- $ count = substr_count ($ token , "\n" );
719- $ line = $ token ->getLine ();
720-
721- for ($ i = $ line ; $ i < $ line + $ count ; $ i ++) {
722- $ this ->ignoredLines [$ filename ][] = $ i ;
723- }
724-
725- if ($ token instanceof PHP_Token_DOC_COMMENT) {
726- // The DOC_COMMENT token does not contain the
727- // final \n character in its text
728- if (substr (trim ($ lines [$ i -1 ]), -2 ) == '*/ ' ) {
729- $ this ->ignoredLines [$ filename ][] = $ i ;
730- }
731- }
732- }
733- break ;
734-
735- case 'PHP_Token_INTERFACE ' :
736- case 'PHP_Token_TRAIT ' :
737- case 'PHP_Token_CLASS ' :
738- case 'PHP_Token_FUNCTION ' :
739- $ docblock = $ token ->getDocblock ();
740-
741- $ this ->ignoredLines [$ filename ][] = $ token ->getLine ();
742-
743- if (strpos ($ docblock , '@codeCoverageIgnore ' )) {
744- $ endLine = $ token ->getEndLine ();
745-
746- for ($ i = $ token ->getLine (); $ i <= $ endLine ; $ i ++) {
747- $ this ->ignoredLines [$ filename ][] = $ i ;
748- }
749- } elseif ($ token instanceof PHP_Token_INTERFACE ||
750- $ token instanceof PHP_Token_TRAIT ||
751- $ token instanceof PHP_Token_CLASS) {
752- if (empty ($ classes [$ token ->getName ()]['methods ' ])) {
753- for ($ i = $ token ->getLine ();
754- $ i <= $ token ->getEndLine ();
755- $ i ++) {
756- $ this ->ignoredLines [$ filename ][] = $ i ;
757- }
758- } else {
759- $ firstMethod = array_shift (
760- $ classes [$ token ->getName ()]['methods ' ]
761- );
762-
763- do {
764- $ lastMethod = array_pop (
765- $ classes [$ token ->getName ()]['methods ' ]
766- );
767- } while ($ lastMethod !== null &&
768- substr ($ lastMethod ['signature ' ], 0 , 18 ) == 'anonymous function ' );
769-
770- if ($ lastMethod === null ) {
771- $ lastMethod = $ firstMethod ;
772- }
773-
774- for ($ i = $ token ->getLine ();
775- $ i < $ firstMethod ['startLine ' ];
776- $ i ++) {
777- $ this ->ignoredLines [$ filename ][] = $ i ;
778- }
779-
780- for ($ i = $ token ->getEndLine ();
781- $ i > $ lastMethod ['endLine ' ];
782- $ i --) {
783- $ this ->ignoredLines [$ filename ][] = $ i ;
784- }
785- }
786- }
787- break ;
788-
789- case 'PHP_Token_NAMESPACE ' :
790- $ this ->ignoredLines [$ filename ][] = $ token ->getEndLine ();
791-
792- // Intentional fallthrough
793- case 'PHP_Token_OPEN_TAG ' :
794- case 'PHP_Token_CLOSE_TAG ' :
795- case 'PHP_Token_USE ' :
796- $ this ->ignoredLines [$ filename ][] = $ token ->getLine ();
797- break ;
798- }
799-
800- if ($ ignore ) {
801- $ this ->ignoredLines [$ filename ][] = $ token ->getLine ();
802-
803- if ($ stop ) {
804- $ ignore = false ;
805- $ stop = false ;
806- }
807- }
808- }
809-
810- $ this ->ignoredLines [$ filename ][] = $ numLines + 1 ;
811-
812- $ this ->ignoredLines [$ filename ] = array_unique (
813- $ this ->ignoredLines [$ filename ]
814- );
815-
816- sort ($ this ->ignoredLines [$ filename ]);
817- }
818-
819- return $ this ->ignoredLines [$ filename ];
820- }
821-
822618 /**
823619 * @param array $data
824620 * @param array $linesToBeCovered
@@ -828,7 +624,7 @@ private function getLinesToBeIgnored($filename)
828624 */
829625 private function performUnintentionallyCoveredCodeCheck (array &$ data , array $ linesToBeCovered , array $ linesToBeUsed )
830626 {
831- $ allowedLines = $ this ->getAllowedLines (
627+ $ allowedLines = $ this ->parser -> getAllowedLines (
832628 $ linesToBeCovered ,
833629 $ linesToBeUsed
834630 );
@@ -855,45 +651,4 @@ private function performUnintentionallyCoveredCodeCheck(array &$data, array $lin
855651 );
856652 }
857653 }
858-
859- /**
860- * @param array $linesToBeCovered
861- * @param array $linesToBeUsed
862- * @return array
863- * @since Method available since Release 2.0.0
864- */
865- private function getAllowedLines (array $ linesToBeCovered , array $ linesToBeUsed )
866- {
867- $ allowedLines = array ();
868-
869- foreach (array_keys ($ linesToBeCovered ) as $ file ) {
870- if (!isset ($ allowedLines [$ file ])) {
871- $ allowedLines [$ file ] = array ();
872- }
873-
874- $ allowedLines [$ file ] = array_merge (
875- $ allowedLines [$ file ],
876- $ linesToBeCovered [$ file ]
877- );
878- }
879-
880- foreach (array_keys ($ linesToBeUsed ) as $ file ) {
881- if (!isset ($ allowedLines [$ file ])) {
882- $ allowedLines [$ file ] = array ();
883- }
884-
885- $ allowedLines [$ file ] = array_merge (
886- $ allowedLines [$ file ],
887- $ linesToBeUsed [$ file ]
888- );
889- }
890-
891- foreach (array_keys ($ allowedLines ) as $ file ) {
892- $ allowedLines [$ file ] = array_flip (
893- array_unique ($ allowedLines [$ file ])
894- );
895- }
896-
897- return $ allowedLines ;
898- }
899654}
0 commit comments