@@ -109,7 +109,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode {
109
109
110
110
/** Gets the constant string value this expression evaluates to, if any. */
111
111
cached
112
- string getStringValue ( ) { none ( ) }
112
+ string getStringValue ( ) { result = getStringValue ( this ) }
113
113
114
114
/** Holds if this expression is impure, that is, its evaluation could have side effects. */
115
115
predicate isImpure ( ) { any ( ) }
@@ -423,8 +423,6 @@ class BigIntLiteral extends @bigintliteral, Literal {
423
423
* ```
424
424
*/
425
425
class StringLiteral extends @stringliteral, Literal {
426
- override string getStringValue ( ) { result = getValue ( ) }
427
-
428
426
/**
429
427
* Gets the value of this string literal parsed as a regular expression, if possible.
430
428
*
@@ -839,8 +837,6 @@ class SeqExpr extends @seqexpr, Expr {
839
837
840
838
override predicate isImpure ( ) { getAnOperand ( ) .isImpure ( ) }
841
839
842
- override string getStringValue ( ) { result = getLastOperand ( ) .getStringValue ( ) }
843
-
844
840
override Expr getUnderlyingValue ( ) { result = getLastOperand ( ) .getUnderlyingValue ( ) }
845
841
}
846
842
@@ -1517,13 +1513,64 @@ class URShiftExpr extends @urshiftexpr, BinaryExpr {
1517
1513
*/
1518
1514
class AddExpr extends @addexpr, BinaryExpr {
1519
1515
override string getOperator ( ) { result = "+" }
1516
+ }
1520
1517
1521
- override string getStringValue ( ) {
1522
- result = getLeftOperand ( ) .getStringValue ( ) + getRightOperand ( ) .getStringValue ( ) and
1523
- result .length ( ) < 1000 * 1000
1524
- }
1518
+ /**
1519
+ * Gets the string value for the expression `e`.
1520
+ * This string-value is either a constant-string, or the result from a simple string-concatenation.
1521
+ */
1522
+ private string getStringValue ( Expr e ) {
1523
+ result = getConstantString ( e )
1524
+ or
1525
+ result = getConcatenatedString ( e )
1526
+ }
1527
+
1528
+ /**
1529
+ * Gets the constant string value for the expression `e`.
1530
+ */
1531
+ private string getConstantString ( Expr e ) {
1532
+ result = getConstantString ( e .getUnderlyingValue ( ) )
1533
+ or
1534
+ result = e .( StringLiteral ) .getValue ( )
1535
+ or
1536
+ exists ( TemplateLiteral lit | lit = e |
1537
+ // fold singletons
1538
+ lit .getNumChildExpr ( ) = 0 and
1539
+ result = ""
1540
+ or
1541
+ e .getNumChildExpr ( ) = 1 and
1542
+ result = getConstantString ( lit .getElement ( 0 ) )
1543
+ )
1544
+ or
1545
+ result = e .( TemplateElement ) .getValue ( )
1546
+ }
1547
+
1548
+ /**
1549
+ * Gets the concatenated string for a string-concatenation `add`.
1550
+ * Only has a result if `add` is not itself an operand in another string-concatenation.
1551
+ */
1552
+ private string getConcatenatedString ( Expr add ) {
1553
+ result = getConcatenatedString ( add .getUnderlyingValue ( ) )
1554
+ or
1555
+ not add = getAnAddOperand ( _) and
1556
+ forex ( Expr leaf | leaf = getAnAddOperand * ( add ) and not exists ( getAnAddOperand ( leaf ) ) |
1557
+ exists ( getConstantString ( leaf ) )
1558
+ ) and
1559
+ result =
1560
+ concat ( Expr leaf |
1561
+ leaf = getAnAddOperand * ( add )
1562
+ |
1563
+ getConstantString ( leaf ) order by leaf .getFirstToken ( ) .getIndex ( )
1564
+ ) and
1565
+ result .length ( ) < 1000 * 1000
1525
1566
}
1526
1567
1568
+ /**
1569
+ * Gets an operand from `add`.
1570
+ * Is specialized to `AddExpr` such that `getAnAddOperand*(add)` can be used to get a leaf from a string-concatenation transitively.
1571
+ */
1572
+ private Expr getAnAddOperand ( AddExpr add ) { result = add .getAnOperand ( ) }
1573
+
1527
1574
/**
1528
1575
* A subtraction expression.
1529
1576
*
0 commit comments