@@ -426,33 +426,354 @@ protected function _testObsoleteConstants($content)
426
426
foreach (self ::$ _constants as $ row ) {
427
427
list ($ constant , $ class , $ replacement ) = $ row ;
428
428
if ($ class ) {
429
- $ fullyQualified = "{$ class }:: {$ constant }" ;
430
- $ regex = preg_quote ($ fullyQualified );
431
- if ($ this ->_isClassOrInterface ($ content , $ class )) {
432
- $ regex .= '| ' . $ this ->_getClassConstantDefinitionRegExp ($ constant )
433
- . '| ' . preg_quote ("self:: {$ constant }" , '/ ' )
434
- . '| ' . preg_quote ("static:: {$ constant }" , '/ ' );
435
- } elseif ($ this ->_isDirectDescendant ($ content , $ class )) {
436
- $ regex .= '| ' . preg_quote ("parent:: {$ constant }" , '/ ' );
437
- if (!$ this ->_isClassConstantDefined ($ content , $ constant )) {
438
- $ regex .= '| ' . preg_quote (
439
- "self:: {$ constant }" ,
440
- '/ '
441
- ) . '| ' . preg_quote (
442
- "static:: {$ constant }" ,
443
- '/ '
429
+ $ class = ltrim ($ class , '\\' );
430
+ $ this ->checkConstantWithFullClasspath ($ constant , $ class , $ replacement , $ content );
431
+ $ this ->checkConstantWithClasspath ($ constant , $ class , $ replacement , $ content );
432
+ } else {
433
+ $ regex = '\b ' . preg_quote ($ constant , '/ ' ) . '\b ' ;
434
+ $ this ->checkExistenceOfObsoleteConstants ($ regex , '' , $ content , $ constant , $ replacement , $ class );
435
+ }
436
+ }
437
+ }
438
+
439
+ /**
440
+ * Build regular expression from Obsolete Constants with correspond to contents
441
+ *
442
+ * @param string $classPartialPath
443
+ * @param string $content
444
+ * @param string $constant
445
+ * @return string
446
+ */
447
+ private function buildRegExFromObsoleteConstant ($ classPartialPath , $ content , $ constant )
448
+ {
449
+ $ regex = preg_quote ("{$ classPartialPath }:: {$ constant }" );
450
+ if ($ this ->_isClassOrInterface ($ content , $ classPartialPath )) {
451
+ $ regex .= '| ' . $ this ->_getClassConstantDefinitionRegExp ($ constant )
452
+ . '| ' . preg_quote ("self:: {$ constant }" , '/ ' )
453
+ . '| ' . preg_quote ("static:: {$ constant }" , '/ ' );
454
+ } elseif ($ this ->_isDirectDescendant ($ content , $ classPartialPath )) {
455
+ $ regex .= '| ' . preg_quote ("parent:: {$ constant }" , '/ ' );
456
+ if (!$ this ->_isClassConstantDefined ($ content , $ constant )) {
457
+ $ regex .= '| ' . preg_quote ("self:: {$ constant }" , '/ ' ) . '| ' . preg_quote ("static:: {$ constant }" , '/ ' );
458
+ }
459
+ }
460
+ return $ regex ;
461
+ }
462
+
463
+ /**
464
+ * Checks condition of using full classpath in 'use' with 'as' (Example: 'use A\B\C as D')
465
+ * where A\B\C is the class where the constant is obsolete
466
+ *
467
+ * @param string $constant
468
+ * @param string $class
469
+ * @param string $replacement
470
+ * @param string $content
471
+ */
472
+ private function checkConstantWithFullClasspath ($ constant , $ class , $ replacement , $ content )
473
+ {
474
+ $ constantRegex = preg_quote ($ constant , '/ ' );
475
+ $ classRegex = preg_quote ($ class );
476
+ $ this ->checkExistenceOfObsoleteConstants (
477
+ $ constantRegex ,
478
+ $ classRegex ,
479
+ $ content ,
480
+ "{$ class }:: {$ constant }" ,
481
+ $ replacement ,
482
+ $ class
483
+ );
484
+ }
485
+
486
+ /**
487
+ * Check all combinations of classpath with constant
488
+ *
489
+ * @param string $constant
490
+ * @param string $class
491
+ * @param string $replacement
492
+ * @param string $content
493
+ */
494
+ private function checkConstantWithClasspath ($ constant , $ class , $ replacement , $ content )
495
+ {
496
+ $ classPathParts = explode ('\\' , $ class );
497
+ $ classPartialPath = '' ;
498
+ for ($ i = count ($ classPathParts ) - 1 ; $ i >= 0 ; $ i --) {
499
+ if ($ i === (count ($ classPathParts ) - 1 )) {
500
+ $ classPartialPath = $ classPathParts [$ i ] . $ classPartialPath ;
501
+ } else {
502
+ $ classPartialPath = $ classPathParts [$ i ] . '\\' . $ classPartialPath ;
503
+ }
504
+ $ constantRegex = $ this ->buildRegExFromObsoleteConstant ($ classPartialPath , $ content , $ constant );
505
+ $ regexClassPartialPath = preg_replace ('/ ' . preg_quote ($ classPartialPath ) . '$/ ' , '' , $ class );
506
+ $ classRegex = preg_quote ($ regexClassPartialPath . $ classPathParts [$ i ]);
507
+ if ($ regexClassPartialPath !== '' ) {
508
+ $ classRegex .= '| ' . preg_quote (rtrim ($ regexClassPartialPath , '\\' ));
509
+ }
510
+ // Checks condition when classpath is distributed over namespace and class definition
511
+ $ classRegexNamespaceClass = '/namespace\s+ ' . preg_quote ('\\' ) . '?( ' . $ classRegex . ')(\s|;)(\r?\n)+ '
512
+ . 'class\s+ ' . preg_quote ('\\' ) . '?( ' . preg_quote (rtrim ($ classPartialPath , '\\' )) . ')\s*/ ' ;
513
+ $ matchNamespaceClass = preg_match ($ classRegexNamespaceClass , $ content );
514
+ $ constantRegexPartial = '/\b(?P<classWithConst>([a-zA-Z0-9_ ' . preg_quote ('\\' ) . ']*))( '
515
+ . preg_quote (':: ' ) . ')* ' . '( ' . preg_quote ($ constant , '/ ' ) . '\b)(\s*|;)/ ' ;
516
+ $ matchConstantPartial = preg_match ($ constantRegexPartial , $ content , $ match );
517
+ if (($ matchNamespaceClass === 1 ) && ($ matchConstantPartial === 1 ) && ($ match ['classWithConst ' ] === '' )) {
518
+ $ this ->assertSame (
519
+ 0 ,
520
+ 1 ,
521
+ $ this ->_suggestReplacement (sprintf ("Constant '%s' is obsolete. " , $ constant ), $ replacement )
522
+ );
523
+ } else {
524
+ $ this ->checkExistenceOfObsoleteConstants (
525
+ $ constantRegex ,
526
+ $ classRegex ,
527
+ $ content ,
528
+ "{$ classPartialPath }:: {$ constant }" ,
529
+ $ replacement ,
530
+ $ class
531
+ );
532
+ }
533
+ }
534
+ }
535
+
536
+ /**
537
+ * Check existence of Obsolete Constant in current content
538
+ *
539
+ * @param string $constantRegex
540
+ * @param string $classRegex
541
+ * @param string $content
542
+ * @param string $constant
543
+ * @param string $replacement
544
+ * @param string $class
545
+ */
546
+ private function checkExistenceOfObsoleteConstants (
547
+ $ constantRegex ,
548
+ $ classRegex ,
549
+ $ content ,
550
+ $ constant ,
551
+ $ replacement ,
552
+ $ class
553
+ ) {
554
+ $ constantRegexFull = '/\b(?P<constPart>((?P<classWithConst>([a-zA-Z0-9_ ' . preg_quote ('\\' ) . ']*))( '
555
+ . preg_quote (':: ' ) . ')* ' . '( ' . $ constantRegex . '\b)))(\s*|;)/ ' ;
556
+ $ matchConstant = preg_match_all ($ constantRegexFull , $ content , $ matchConstantString );
557
+ $ result = 0 ;
558
+ if ($ matchConstant === 1 ) {
559
+ if ($ classRegex !== '' ) {
560
+ $ classRegexFull = '/(?P<useOrNamespace>(use|namespace))\s+(?P<classPath>( ' . preg_quote ('\\' )
561
+ . '?( ' . $ classRegex . ')))(\s+as\s+(?P<classAlias>([\w\d_]+)))?(\s|;)/ ' ;
562
+ $ matchClass = preg_match ($ classRegexFull , $ content , $ matchClassString );
563
+ if ($ matchClass === 1 ) {
564
+ if ($ matchClassString ['classAlias ' ]) {
565
+ $ result = $ this ->checkAliasUseNamespace (
566
+ $ constantRegex ,
567
+ $ matchConstantString ,
568
+ $ matchClassString ,
569
+ $ class
444
570
);
571
+ } else {
572
+ $ result = $ this ->checkNoAliasUseNamespace ($ matchConstantString , $ matchClassString , $ class );
573
+ }
574
+ } else {
575
+ foreach ($ matchConstantString ['classWithConst ' ] as $ constantMatch ) {
576
+ if (trim ($ constantMatch , '\\' ) === $ class ) {
577
+ $ result = 1 ;
578
+ break ;
579
+ }
445
580
}
581
+
446
582
}
447
583
} else {
448
- $ fullyQualified = $ constant ;
449
- $ regex = preg_quote ($ constant , '/ ' );
584
+ $ result = 1 ;
450
585
}
451
- $ this ->_assertNotRegExp (
452
- '/[^a-z\d_]( ' . $ regex . ')[^a-z\d_]/iS ' ,
453
- $ content ,
454
- $ this ->_suggestReplacement (sprintf ("Constant '%s' is obsolete. " , $ fullyQualified ), $ replacement )
586
+ }
587
+ $ this ->assertSame (
588
+ 0 ,
589
+ $ result ,
590
+ $ this ->_suggestReplacement (sprintf ("Constant '%s' is obsolete. " , $ constant ), $ replacement )
591
+ );
592
+ }
593
+
594
+ /**
595
+ * Check proper usage of 'as' alias in 'use' or 'namespace' in context of constant
596
+ *
597
+ * @param string $constantRegex
598
+ * @param string $matchConstantString
599
+ * @param string $matchClassString
600
+ * @param string $class
601
+ * @return int
602
+ */
603
+ private function checkAliasUseNamespace (
604
+ $ constantRegex ,
605
+ $ matchConstantString ,
606
+ $ matchClassString ,
607
+ $ class
608
+ ) {
609
+ $ foundProperUse = false ;
610
+ $ foundAsComponent = false ;
611
+ $ asComponent = $ matchClassString ['classAlias ' ];
612
+ foreach ($ matchConstantString ['constPart ' ] as $ constantMatch ) {
613
+ $ expectedOnlyConst = '/ ' . $ asComponent . preg_quote (':: ' ) . $ constantRegex . '/ ' ;
614
+ $ expectedConstPartialClass = '/ ' . $ asComponent . preg_quote ('\\' )
615
+ . $ constantRegex . '/ ' ;
616
+ if ((preg_match ($ expectedOnlyConst , $ constantMatch ) === 1 )
617
+ || (preg_match ($ expectedConstPartialClass , $ constantMatch ) === 1 )) {
618
+ $ foundAsComponent = true ;
619
+ }
620
+ if (strpos ($ constantMatch , ':: ' ) !== false ) {
621
+ $ foundProperUse = $ this ->checkCompletePathOfClass (
622
+ $ constantMatch ,
623
+ $ matchClassString ,
624
+ $ class ,
625
+ $ foundAsComponent ,
626
+ $ asComponent
627
+ );
628
+ if ($ foundProperUse ) {
629
+ break ;
630
+ }
631
+ }
632
+ }
633
+ if ($ foundProperUse ) {
634
+ return 1 ;
635
+ } else {
636
+ return 0 ;
637
+ }
638
+ }
639
+
640
+ /**
641
+ * Check proper usage of classpath in constant and 'use'/'namespace' when there is no 'as' alias
642
+ *
643
+ * @param string $matchConstantString
644
+ * @param string $matchClassString
645
+ * @param string $class
646
+ * @return int
647
+ */
648
+ private function checkNoAliasUseNamespace (
649
+ $ matchConstantString ,
650
+ $ matchClassString ,
651
+ $ class
652
+ ) {
653
+ $ foundProperUse = false ;
654
+ foreach ($ matchConstantString ['constPart ' ] as $ constantMatch ) {
655
+ $ foundProperUse = $ this ->checkCompletePathOfClass (
656
+ $ constantMatch ,
657
+ $ matchClassString ,
658
+ $ class
455
659
);
660
+ if ($ foundProperUse ) {
661
+ break ;
662
+ }
663
+ }
664
+ if ($ foundProperUse ) {
665
+ return 1 ;
666
+ } else {
667
+ return 0 ;
668
+ }
669
+ }
670
+
671
+ /**
672
+ * Check if class path with constant and in 'use' or 'namespace' forms complete classpath
673
+ *
674
+ * @param string $constantMatch
675
+ * @param array $matchClassString
676
+ * @param string $class
677
+ * @param bool $foundAsComponent
678
+ * @param string $asComponent
679
+ * @return bool
680
+ */
681
+ private function checkCompletePathOfClass (
682
+ $ constantMatch ,
683
+ $ matchClassString ,
684
+ $ class ,
685
+ $ foundAsComponent = false ,
686
+ $ asComponent = ''
687
+ ) {
688
+ $ temp = explode (':: ' , $ constantMatch );
689
+ $ pathWithConst = trim (ltrim (str_replace ('\\\\' , '\\' , $ temp [0 ]), '\\' ));
690
+ if ($ pathWithConst === $ class ) {
691
+ return true ;
692
+ }
693
+ if ($ foundAsComponent ) {
694
+ $ pathWithConst = ltrim (preg_replace ('/^ ' . $ asComponent . '/ ' , '' , $ pathWithConst ), '\\' );
695
+ if ($ pathWithConst === '' ) {
696
+ return true ;
697
+ }
698
+ }
699
+ $ pathWithConstParts = explode ('\\' , $ pathWithConst );
700
+ $ pathInUseNamespace = trim ($ matchClassString ['classPath ' ], '\\' );
701
+ $ pathInUseNamespaceTruncated = trim (trim (
702
+ preg_replace (
703
+ '/ ' . preg_quote ($ pathWithConstParts [0 ]) . '$/ ' ,
704
+ '' ,
705
+ $ pathInUseNamespace
706
+ ),
707
+ '\\'
708
+ ));
709
+ if ($ this ->checkClasspathProperDivisionNoConstantPath (
710
+ $ pathInUseNamespaceTruncated ,
711
+ $ pathInUseNamespace ,
712
+ $ matchClassString ,
713
+ $ class ,
714
+ $ foundAsComponent
715
+ )) {
716
+ return true ;
717
+ } else {
718
+ return $ this ->checkClasspathProperDivisionWithConstantPath (
719
+ $ pathInUseNamespaceTruncated ,
720
+ $ pathInUseNamespace ,
721
+ $ pathWithConst ,
722
+ $ class ,
723
+ $ foundAsComponent
724
+ );
725
+ }
726
+ }
727
+
728
+ /**
729
+ * Check if classpath is divided in two places with correct constant name
730
+ *
731
+ * @param string $pathInUseNamespaceTruncated
732
+ * @param string $pathInUseNamespace
733
+ * @param array $matchClassString
734
+ * @param string $class
735
+ * @param bool $foundAsComponent
736
+ * @return bool
737
+ */
738
+ private function checkClasspathProperDivisionNoConstantPath (
739
+ $ pathInUseNamespaceTruncated ,
740
+ $ pathInUseNamespace ,
741
+ $ matchClassString ,
742
+ $ class ,
743
+ $ foundAsComponent
744
+ ) {
745
+ if ($ pathInUseNamespaceTruncated === $ pathInUseNamespace && $ pathInUseNamespaceTruncated !== $ class
746
+ && ($ foundAsComponent || (strpos ($ matchClassString ['useOrNamespace ' ], 'namespace ' ) !== false ))) {
747
+ return true ;
748
+ } else {
749
+ return false ;
750
+ }
751
+ }
752
+
753
+ /**
754
+ * Check if classpath is divided in two places with constant properly with or without alias
755
+ *
756
+ * @param string $pathInUseNamespaceTruncated
757
+ * @param string $pathInUseNamespace
758
+ * @param string $pathWithConst
759
+ * @param string $class
760
+ * @param bool $foundAsComponent
761
+ * @return bool
762
+ */
763
+ private function checkClasspathProperDivisionWithConstantPath (
764
+ $ pathInUseNamespaceTruncated ,
765
+ $ pathInUseNamespace ,
766
+ $ pathWithConst ,
767
+ $ class ,
768
+ $ foundAsComponent
769
+ ) {
770
+ if ((($ pathInUseNamespaceTruncated . '\\' . $ pathWithConst === $ class )
771
+ && ($ pathInUseNamespaceTruncated !== $ pathInUseNamespace ) && !$ foundAsComponent )
772
+ || (($ pathInUseNamespaceTruncated === $ class ) && (strpos ($ pathWithConst , '\\' ) === false )
773
+ && $ foundAsComponent )) {
774
+ return true ;
775
+ } else {
776
+ return false ;
456
777
}
457
778
}
458
779
@@ -465,7 +786,7 @@ protected function _testObsoleteConstants($content)
465
786
*/
466
787
protected function _isClassConstantDefined ($ content , $ constant )
467
788
{
468
- return (bool )preg_match ('/ ' . $ this ->_getClassConstantDefinitionRegExp ($ constant ) . '/iS ' , $ content );
789
+ return (bool )preg_match ('/ ' . $ this ->_getClassConstantDefinitionRegExp ($ constant ) . '/S ' , $ content );
469
790
}
470
791
471
792
/**
0 commit comments