@@ -42,7 +42,8 @@ newtype SynthKind =
42
42
StmtSequenceKind ( ) or
43
43
SelfKind ( SelfVariable v ) or
44
44
SubExprKind ( ) or
45
- ConstantReadAccessKind ( string value ) { any ( Synthesis s ) .constantReadAccess ( value ) }
45
+ ConstantReadAccessKind ( string value ) { any ( Synthesis s ) .constantReadAccess ( value ) } or
46
+ ConstantWriteAccessKind ( string value ) { any ( Synthesis s ) .constantWriteAccess ( value ) }
46
47
47
48
/**
48
49
* An AST child.
@@ -107,6 +108,11 @@ class Synthesis extends TSynthesis {
107
108
*/
108
109
predicate constantReadAccess ( string name ) { none ( ) }
109
110
111
+ /**
112
+ * Holds if a constant write access of `name` is needed.
113
+ */
114
+ predicate constantWriteAccess ( string name ) { none ( ) }
115
+
110
116
/**
111
117
* Holds if `n` should be excluded from `ControlFlowTree` in the CFG construction.
112
118
*/
@@ -493,6 +499,231 @@ private module AssignOperationDesugar {
493
499
}
494
500
}
495
501
502
+ /**
503
+ * An assignment operation where the left-hand side is a constant
504
+ * without scope expression, such as`FOO` or `::Foo`.
505
+ */
506
+ private class ConstantAssignOperation extends AssignOperation {
507
+ string name ;
508
+
509
+ pragma [ nomagic]
510
+ ConstantAssignOperation ( ) {
511
+ name =
512
+ any ( Ruby:: Constant constant | TTokenConstantAccess ( constant ) = this .getLeftOperand ( ) )
513
+ .getValue ( )
514
+ or
515
+ name =
516
+ "::" +
517
+ any ( Ruby:: Constant constant |
518
+ TScopeResolutionConstantAccess ( any ( Ruby:: ScopeResolution g | not exists ( g .getScope ( ) ) ) ,
519
+ constant ) = this .getLeftOperand ( )
520
+ ) .getValue ( )
521
+ }
522
+
523
+ final string getName ( ) { result = name }
524
+ }
525
+
526
+ pragma [ nomagic]
527
+ private predicate constantAssignOperationSynthesis ( AstNode parent , int i , Child child ) {
528
+ exists ( ConstantAssignOperation cao |
529
+ parent = cao and
530
+ i = - 1 and
531
+ child = SynthChild ( AssignExprKind ( ) )
532
+ or
533
+ exists ( AstNode assign | assign = TAssignExprSynth ( cao , - 1 ) |
534
+ parent = assign and
535
+ i = 0 and
536
+ child = childRef ( cao .getLeftOperand ( ) )
537
+ or
538
+ parent = assign and
539
+ i = 1 and
540
+ child = SynthChild ( getKind ( cao ) )
541
+ or
542
+ parent = getSynthChild ( assign , 1 ) and
543
+ (
544
+ i = 0 and
545
+ child = SynthChild ( ConstantReadAccessKind ( cao .getName ( ) ) )
546
+ or
547
+ i = 1 and
548
+ child = childRef ( cao .getRightOperand ( ) )
549
+ )
550
+ )
551
+ )
552
+ }
553
+
554
+ /**
555
+ * ```rb
556
+ * FOO += y
557
+ * ```
558
+ *
559
+ * desugars to
560
+ *
561
+ * ```rb
562
+ * FOO = FOO + y
563
+ * ```
564
+ */
565
+ private class ConstantAssignOperationSynthesis extends Synthesis {
566
+ final override predicate child ( AstNode parent , int i , Child child ) {
567
+ constantAssignOperationSynthesis ( parent , i , child )
568
+ }
569
+
570
+ final override predicate constantReadAccess ( string name ) {
571
+ name = any ( ConstantAssignOperation o ) .getName ( )
572
+ }
573
+
574
+ final override predicate location ( AstNode n , Location l ) {
575
+ exists ( ConstantAssignOperation cao , BinaryOperation bo |
576
+ bo = cao .getDesugared ( ) .( AssignExpr ) .getRightOperand ( )
577
+ |
578
+ n = bo and
579
+ l = getAssignOperationLocation ( cao )
580
+ or
581
+ n = bo .getLeftOperand ( ) and
582
+ hasLocation ( cao .getLeftOperand ( ) , l )
583
+ )
584
+ }
585
+ }
586
+
587
+ /**
588
+ * An assignment operation where the left-hand side is a constant
589
+ * with scope expression, such as `expr::FOO`.
590
+ */
591
+ private class ScopeResolutionAssignOperation extends AssignOperation {
592
+ string name ;
593
+ Expr scope ;
594
+
595
+ pragma [ nomagic]
596
+ ScopeResolutionAssignOperation ( ) {
597
+ exists ( Ruby:: Constant constant , Ruby:: ScopeResolution g |
598
+ TScopeResolutionConstantAccess ( g , constant ) = this .getLeftOperand ( ) and
599
+ name = constant .getValue ( ) and
600
+ toGenerated ( scope ) = g .getScope ( )
601
+ )
602
+ }
603
+
604
+ final string getName ( ) { result = name }
605
+
606
+ final Expr getScopeExpr ( ) { result = scope }
607
+ }
608
+
609
+ pragma [ nomagic]
610
+ private predicate scopeResolutionAssignOperationSynthesis ( AstNode parent , int i , Child child ) {
611
+ exists ( ScopeResolutionAssignOperation cao |
612
+ parent = cao and
613
+ i = - 1 and
614
+ child = SynthChild ( StmtSequenceKind ( ) )
615
+ or
616
+ exists ( AstNode stmts | stmts = TStmtSequenceSynth ( cao , - 1 ) |
617
+ parent = stmts and
618
+ i = 0 and
619
+ child = SynthChild ( AssignExprKind ( ) )
620
+ or
621
+ exists ( AstNode assign | assign = TAssignExprSynth ( stmts , 0 ) |
622
+ parent = assign and
623
+ i = 0 and
624
+ child = SynthChild ( LocalVariableAccessSynthKind ( TLocalVariableSynth ( cao , 0 ) ) )
625
+ or
626
+ parent = assign and
627
+ i = 1 and
628
+ child = childRef ( cao .getScopeExpr ( ) )
629
+ )
630
+ or
631
+ parent = stmts and
632
+ i = 1 and
633
+ child = SynthChild ( AssignExprKind ( ) )
634
+ or
635
+ exists ( AstNode assign | assign = TAssignExprSynth ( stmts , 1 ) |
636
+ parent = assign and
637
+ i = 0 and
638
+ child = SynthChild ( ConstantWriteAccessKind ( cao .getName ( ) ) )
639
+ or
640
+ exists ( AstNode cwa | cwa = TConstantWriteAccessSynth ( assign , 0 , cao .getName ( ) ) |
641
+ parent = cwa and
642
+ i = 0 and
643
+ child = SynthChild ( LocalVariableAccessSynthKind ( TLocalVariableSynth ( cao , 0 ) ) )
644
+ )
645
+ or
646
+ parent = assign and
647
+ i = 1 and
648
+ child = SynthChild ( getKind ( cao ) )
649
+ or
650
+ exists ( AstNode op | op = getSynthChild ( assign , 1 ) |
651
+ parent = op and
652
+ i = 0 and
653
+ child = SynthChild ( ConstantReadAccessKind ( cao .getName ( ) ) )
654
+ or
655
+ exists ( AstNode cra | cra = TConstantReadAccessSynth ( op , 0 , cao .getName ( ) ) |
656
+ parent = cra and
657
+ i = 0 and
658
+ child = SynthChild ( LocalVariableAccessSynthKind ( TLocalVariableSynth ( cao , 0 ) ) )
659
+ )
660
+ or
661
+ parent = op and
662
+ i = 1 and
663
+ child = childRef ( cao .getRightOperand ( ) )
664
+ )
665
+ )
666
+ )
667
+ )
668
+ }
669
+
670
+ /**
671
+ * ```rb
672
+ * expr::FOO += y
673
+ * ```
674
+ *
675
+ * desugars to
676
+ *
677
+ * ```rb
678
+ * __synth__0 = expr
679
+ * __synth__0::FOO = _synth__0::FOO + y
680
+ * ```
681
+ */
682
+ private class ScopeResolutionAssignOperationSynthesis extends Synthesis {
683
+ final override predicate child ( AstNode parent , int i , Child child ) {
684
+ scopeResolutionAssignOperationSynthesis ( parent , i , child )
685
+ }
686
+
687
+ final override predicate constantReadAccess ( string name ) {
688
+ name = any ( ScopeResolutionAssignOperation o ) .getName ( )
689
+ }
690
+
691
+ final override predicate localVariable ( AstNode n , int i ) {
692
+ n instanceof ScopeResolutionAssignOperation and
693
+ i = 0
694
+ }
695
+
696
+ final override predicate constantWriteAccess ( string name ) { this .constantReadAccess ( name ) }
697
+
698
+ final override predicate location ( AstNode n , Location l ) {
699
+ exists ( ScopeResolutionAssignOperation cao , StmtSequence stmts | stmts = cao .getDesugared ( ) |
700
+ n = stmts .getStmt ( 0 ) and
701
+ hasLocation ( cao .getScopeExpr ( ) , l )
702
+ or
703
+ exists ( AssignExpr assign | assign = stmts .getStmt ( 1 ) |
704
+ n = assign and hasLocation ( cao , l )
705
+ or
706
+ n = assign .getLeftOperand ( ) and
707
+ hasLocation ( cao .getLeftOperand ( ) , l )
708
+ or
709
+ n = assign .getLeftOperand ( ) .( ConstantAccess ) .getScopeExpr ( ) and
710
+ hasLocation ( cao .getScopeExpr ( ) , l )
711
+ or
712
+ exists ( BinaryOperation bo | bo = assign .getRightOperand ( ) |
713
+ n = bo and
714
+ l = getAssignOperationLocation ( cao )
715
+ or
716
+ n = bo .getLeftOperand ( ) and
717
+ hasLocation ( cao .getLeftOperand ( ) , l )
718
+ or
719
+ n = bo .getLeftOperand ( ) .( ConstantAccess ) .getScopeExpr ( ) and
720
+ hasLocation ( cao .getScopeExpr ( ) , l )
721
+ )
722
+ )
723
+ )
724
+ }
725
+ }
726
+
496
727
/** An assignment operation where the left-hand side is a method call. */
497
728
private class SetterAssignOperation extends AssignOperation {
498
729
private MethodCall mc ;
0 commit comments