-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathExpr.qll
More file actions
2290 lines (1953 loc) · 52 KB
/
Expr.qll
File metadata and controls
2290 lines (1953 loc) · 52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/**
* Provides classes for working with expressions.
*/
import go
/**
* An expression.
*
* Examples:
*
* ```go
* x + 1
* y < 0
* ```
*/
class Expr extends @expr, ExprParent {
/**
* Gets the kind of this expression, which is an integer value representing the expression's
* node type.
*
* Note that the mapping from node types to integer kinds is considered an implementation detail
* and subject to change without notice.
*/
int getKind() { exprs(this, result, _, _) }
/** Gets this expression, with any surrounding parentheses removed. */
Expr stripParens() { result = this }
/**
* Holds if this expression is constant, that is, if its value is determined at
* compile-time.
*/
predicate isConst() { constvalues(this, _, _) }
/**
* Gets the boolean value this expression evalutes to, if any.
*/
boolean getBoolValue() {
this.getType().getUnderlyingType() instanceof BoolType and
exists(string val | constvalues(this, val, _) |
val = "true" and result = true
or
val = "false" and result = false
)
}
/** Gets the floating-point value this expression evaluates to, if any. */
float getFloatValue() {
this.getType().getUnderlyingType() instanceof FloatType and
exists(string val | constvalues(this, val, _) | result = val.toFloat())
}
/**
* Gets the integer value this expression evaluates to, if any.
*
* Note that this does not have a result if the value is too large to fit in a
* 32-bit signed integer type.
*/
int getIntValue() {
this.getType().getUnderlyingType() instanceof IntegerType and
exists(string val | constvalues(this, val, _) | result = val.toInt())
}
/** Gets either `getFloatValue` or `getIntValue`. */
float getNumericValue() { result = this.getFloatValue() or result = this.getIntValue() }
/**
* Holds if the complex value this expression evaluates to has real part `real` and imaginary
* part `imag`.
*/
predicate hasComplexValue(float real, float imag) {
this.getType().getUnderlyingType() instanceof ComplexType and
exists(string val | constvalues(this, val, _) |
exists(string cmplxre |
cmplxre = "^\\((.+) \\+ (.+)i\\)$" and
real = val.regexpCapture(cmplxre, 1).toFloat() and
imag = val.regexpCapture(cmplxre, 2).toFloat()
)
)
}
/** Gets the string value this expression evaluates to, if any. */
string getStringValue() {
this.getType().getUnderlyingType() instanceof StringType and
constvalues(this, result, _)
}
/**
* Gets the string representation of the exact value this expression
* evaluates to, if any.
*
* For example, for the constant 3.141592653589793238462, this will
* result in 1570796326794896619231/500000000000000000000
*/
string getExactValue() { constvalues(this, _, result) }
/**
* Holds if this expression has a constant value which is guaranteed not to depend on the
* platform where it is evaluated.
*
* This is a conservative approximation, that is, the predicate may fail to hold for expressions
* whose value is platform independent, but it will never hold for expressions whose value is not
* platform independent.
*
* Examples of platform-dependent constants include constants declared in files with build
* constraints, the value of `runtime.GOOS`, and the return value of `unsafe.Sizeof`.
*/
predicate isPlatformIndependentConstant() { none() }
/** Gets the type of this expression. */
Type getType() {
type_of(this, result)
or
not type_of(this, _) and
result instanceof InvalidType
}
/**
* Gets the global value number of this expression.
*
* Expressions with the same global value number are guaranteed to have the same value at runtime.
* The converse does not hold in general, that is, expressions with different global value numbers
* may still have the same value at runtime.
*/
GVN getGlobalValueNumber() { result = globalValueNumber(DataFlow::exprNode(this)) }
/**
* Holds if this expression may have observable side effects of its own (that is, independent
* of whether its sub-expressions may have side effects).
*
* Memory allocation is not considered an observable side effect.
*/
predicate mayHaveOwnSideEffects() { none() }
/**
* Holds if the evaluation of this expression may produce observable side effects.
*
* Memory allocation is not considered an observable side effect.
*/
predicate mayHaveSideEffects() {
this.mayHaveOwnSideEffects() or this.getAChildExpr().mayHaveSideEffects()
}
override string toString() { result = "expression" }
}
/**
* A bad expression, that is, an expression that could not be parsed.
*
* Examples:
*
* ```go
* x +
* y <
* ```
*/
class BadExpr extends @badexpr, Expr {
override string toString() { result = "bad expression" }
override string getAPrimaryQlClass() { result = "BadExpr" }
}
/**
* An identifier.
*
* Examples:
*
* ```go
* x
* ```
*/
class Ident extends @ident, Expr {
/** Gets the name of this identifier. */
string getName() { literals(this, result, _) }
/** Holds if this identifier is a use of `e`. */
predicate uses(Entity e) { uses(this, e) }
/** Holds if this identifier is a definition or declaration of `e` */
predicate declares(Entity e) { defs(this, e) }
/** Holds if this identifier refers to (that is, uses, defines or declares) `e`. */
predicate refersTo(Entity e) { this.uses(e) or this.declares(e) }
override string toString() { result = this.getName() }
override string getAPrimaryQlClass() { result = "Ident" }
}
/**
* The blank identifier `_`.
*
* Examples:
*
* ```go
* _
* ```
*/
class BlankIdent extends Ident {
BlankIdent() { this.getName() = "_" }
override string getAPrimaryQlClass() { result = "BlankIdent" }
}
/**
* An ellipsis expression, representing either the `...` type in a parameter list or
* the `...` length in an array type.
*
* Examples:
*
* ```go
* ...
* ```
*/
class Ellipsis extends @ellipsis, Expr {
/** Gets the operand of this ellipsis expression. */
Expr getOperand() { result = this.getChildExpr(0) }
override string toString() { result = "..." }
override string getAPrimaryQlClass() { result = "Ellipsis" }
}
/**
* A literal expression.
*
* Examples:
*
* ```go
* "hello"
* func(x, y int) int { return x + y }
* map[string]int{"A": 1, "B": 2}
* ```
*/
class Literal extends Expr {
Literal() {
this instanceof @basiclit or this instanceof @funclit or this instanceof @compositelit
}
}
/**
* A literal expression of basic type.
*
* Examples:
*
* ```go
* 1
* "hello"
* ```
*/
class BasicLit extends @basiclit, Literal {
/** Gets the value of this literal expressed as a string. */
string getValue() { literals(this, result, _) }
/** Gets the raw program text corresponding to this literal. */
string getText() { literals(this, _, result) }
override predicate isConst() {
// override to make sure literals are always considered constants even if we did not get
// information about constant values from the extractor (for example due to missing
// type information)
any()
}
override predicate isPlatformIndependentConstant() { any() }
override string toString() { result = this.getText() }
}
/**
* An integer literal.
*
* Examples:
*
* ```go
* 256
* ```
*/
class IntLit extends @intlit, BasicLit {
override string getAPrimaryQlClass() { result = "IntLit" }
}
/**
* A floating-point literal.
*
* Examples:
*
* ```go
* 2.71828
* ```
*/
class FloatLit extends @floatlit, BasicLit {
override string getAPrimaryQlClass() { result = "FloatLit" }
}
/**
* An imaginary literal.
*
* Examples:
*
* ```go
* 2i
* 2.7i
* ```
*/
class ImagLit extends @imaglit, BasicLit {
override string getAPrimaryQlClass() { result = "ImagLit" }
}
/**
* A rune literal.
*
* Examples:
*
* ```go
* 'a'
* 'ä'
* '本'
* '\377'
* '\xff'
* '\u12e4'
* '\U00101234'
* '\n'
* ```
*/
class CharLit extends @charlit, BasicLit {
// use the constant value of the literal as the string value, as the value we get from the
// compiler is an integer, meaning we would not otherwise have a string value for rune literals
override string getStringValue() { result = this.getValue() }
override string getAPrimaryQlClass() { result = "CharLit" }
}
class RuneLit = CharLit;
/**
* A string literal.
*
* Examples:
*
* ```go
* "hello world"
* ```
*/
class StringLit extends @stringlit, BasicLit {
override string getAPrimaryQlClass() { result = "StringLit" }
/** Holds if this string literal is a raw string literal. */
predicate isRaw() { this.getText().matches("`%`") }
}
/**
* A function literal.
*
* Examples:
*
* ```go
* func(x, y int) int { return x + y }
* ```
*/
class FuncLit extends @funclit, Literal, StmtParent, FuncDef {
override FuncTypeExpr getTypeExpr() { result = this.getChildExpr(0) }
override SignatureType getType() { result = Literal.super.getType() }
/** Gets the body of this function literal. */
override BlockStmt getBody() { result = this.getChildStmt(1) }
override predicate isPlatformIndependentConstant() { any() }
override string toString() { result = "function literal" }
override string getAPrimaryQlClass() { result = "FuncLit" }
}
/**
* A composite literal
*
* Examples:
*
* ```go
* Point3D{0.5, -0.5, 0.5}
* map[string]int{"A": 1, "B": 2}
* ```
*/
class CompositeLit extends @compositelit, Literal {
/** Gets the expression representing the type of this composite literal. */
Expr getTypeExpr() { result = this.getChildExpr(0) }
/** Gets the `i`th element of this composite literal (0-based). */
Expr getElement(int i) {
i >= 0 and
result = this.getChildExpr(i + 1)
}
/** Gets an element of this composite literal. */
Expr getAnElement() { result = this.getElement(_) }
/** Gets the number of elements in this composite literal. */
int getNumElement() { result = count(this.getAnElement()) }
/**
* Gets the `i`th key expression in this literal.
*
* If the `i`th element of this literal has no key, this predicate is undefined for `i`.
*/
Expr getKey(int i) { result = this.getElement(i).(KeyValueExpr).getKey() }
/**
* Gets the `i`th value expression in this literal.
*/
Expr getValue(int i) {
exists(Expr elt | elt = this.getElement(i) |
result = elt.(KeyValueExpr).getValue()
or
not elt instanceof KeyValueExpr and result = elt
)
}
override string toString() { result = "composite literal" }
override string getAPrimaryQlClass() { result = "CompositeLit" }
}
/**
* A map literal.
*
* Examples:
*
* ```go
* map[string]int{"A": 1, "B": 2}
* ```
*/
class MapLit extends CompositeLit {
MapType mt;
MapLit() { mt = this.getType().getUnderlyingType() }
/** Gets the key type of this literal. */
Type getKeyType() { result = mt.getKeyType() }
/** Gets the value type of this literal. */
Type getValueType() { result = mt.getValueType() }
override string toString() { result = "map literal" }
override string getAPrimaryQlClass() { result = "MapLit" }
}
/**
* A struct literal.
*
* Examples:
*
* ```go
* Point3D{0.5, -0.5, 0.5}
* Point3D{y: 1}
* Point3D{}
* ```
*/
class StructLit extends CompositeLit {
StructType st;
StructLit() { st = this.getType().getUnderlyingType() }
/** Gets the struct type underlying this literal. */
StructType getStructType() { result = st }
override string toString() { result = "struct literal" }
override string getAPrimaryQlClass() { result = "StructLit" }
}
/**
* An array or slice literal.
*
* Examples:
*
* ```go
* [10]string{}
* [6]int{1, 2, 3, 5}
* [...]string{"Sat", "Sun"}
* []int{1, 2, 3, 5}
* []string{"Sat", "Sun"}
* ```
*/
class ArrayOrSliceLit extends CompositeLit {
CompositeType type;
ArrayOrSliceLit() {
type = this.getType().getUnderlyingType() and
(
type instanceof ArrayType
or
type instanceof SliceType
)
}
}
/**
* An array literal.
*
* Examples:
*
* ```go
* [10]string{}
* [6]int{1, 2, 3, 5}
* [...]string{"Sat", "Sun"}
* ```
*/
class ArrayLit extends ArrayOrSliceLit {
override ArrayType type;
/** Gets the array type underlying this literal. */
ArrayType getArrayType() { result = type }
override string toString() { result = "array literal" }
override string getAPrimaryQlClass() { result = "ArrayLit" }
}
/**
* A slice literal.
*
* Examples:
*
* ```go
* []int{1, 2, 3, 5}
* []string{"Sat", "Sun"}
* ```
*/
class SliceLit extends ArrayOrSliceLit {
override SliceType type;
/** Gets the slice type underlying this literal. */
SliceType getSliceType() { result = type }
override string toString() { result = "slice literal" }
override string getAPrimaryQlClass() { result = "SliceLit" }
}
/**
* A parenthesized expression.
*
* Examples:
*
* ```go
* (x + y)
* ```
*/
class ParenExpr extends @parenexpr, Expr {
/** Gets the expression between parentheses. */
Expr getExpr() { result = this.getChildExpr(0) }
override Expr stripParens() { result = this.getExpr().stripParens() }
override predicate isPlatformIndependentConstant() {
this.getExpr().isPlatformIndependentConstant()
}
override string toString() { result = "(...)" }
override string getAPrimaryQlClass() { result = "ParenExpr" }
}
/**
* A selector expression, that is, a base expression followed by a selector.
*
* Examples:
*
* ```go
* x.f
* ```
*/
class SelectorExpr extends @selectorexpr, Expr {
/** Gets the base of this selector expression. */
Expr getBase() { result = this.getChildExpr(0) }
/** Gets the selector of this selector expression. */
Ident getSelector() { result = this.getChildExpr(1) }
/** Holds if this selector is a use of `e`. */
predicate uses(Entity e) { this.getSelector().uses(e) }
/** Holds if this selector is a definition of `e` */
predicate declares(Entity e) { this.getSelector().declares(e) }
/** Holds if this selector refers to (that is, uses, defines or declares) `e`. */
predicate refersTo(Entity e) { this.getSelector().refersTo(e) }
override predicate mayHaveOwnSideEffects() { any() }
override string toString() { result = "selection of " + this.getSelector() }
override string getAPrimaryQlClass() { result = "SelectorExpr" }
}
/**
* A selector expression that refers to a promoted field or a promoted method. These
* selectors may implicitly address an embedded struct of their base type - for example,
* the selector `x.field` may implicitly address `x.Embedded.field`). Note they may also
* explicitly address `field`; being a `PromotedSelector` only indicates the addressed
* field or method may be promoted, not that it is promoted in this particular context.
*/
class PromotedSelector extends SelectorExpr {
PromotedSelector() {
exists(ValueEntity ve | this.refersTo(ve) |
ve instanceof PromotedField or ve instanceof PromotedMethod
)
}
/**
* Gets the underlying struct type of this selector's base. Note because this selector
* addresses a promoted field, the addressed field may not directly occur in the returned
* struct type.
*/
StructType getSelectedStructType() {
exists(Type baseType | baseType = this.getBase().getType().getUnderlyingType() |
pragma[only_bind_into](result) =
[baseType, baseType.(PointerType).getBaseType().getUnderlyingType()]
)
}
}
/**
* An index expression, that is, a base expression followed by an index.
* Expressions which represent generic type instantiations have been
* excluded.
*
* Examples:
*
* ```go
* array[i]
* arrayptr[i]
* slice[i]
* map[key]
* ```
*/
class IndexExpr extends @indexexpr, Expr {
IndexExpr() { not isTypeExprBottomUp(this.getChildExpr(0)) }
/** Gets the base of this index expression. */
Expr getBase() { result = this.getChildExpr(0) }
/** Gets the index of this index expression. */
Expr getIndex() { result = this.getChildExpr(1) }
override predicate mayHaveOwnSideEffects() { any() }
override string toString() { result = "index expression" }
override string getAPrimaryQlClass() { result = "IndexExpr" }
}
/**
* A generic function instantiation, that is, a base expression that represents
* a generic function, followed by a list of type arguments.
*
* Examples:
*
* ```go
* genericfunction[type]
* genericfunction[type1, type2]
* ```
*/
class GenericFunctionInstantiationExpr extends @genericfunctioninstantiationexpr, Expr {
/** Gets the generic function expression. */
Expr getBase() { result = this.getChildExpr(0) }
/** Gets the `i`th type argument. */
Expr getTypeArgument(int i) {
i >= 0 and
result = this.getChildExpr(i + 1)
}
override predicate mayHaveOwnSideEffects() { any() }
override string toString() { result = "generic function instantiation expression" }
override string getAPrimaryQlClass() { result = "GenericFunctionInstantiationExpr" }
}
/**
* A generic type instantiation, that is, a base expression that is a generic
* type followed by a list of type arguments.
*
* Examples:
*
* ```go
* generictype[type]
* generictype[type1, type2]
* ```
*/
class GenericTypeInstantiationExpr extends Expr {
GenericTypeInstantiationExpr() {
this instanceof @generictypeinstantiationexpr
or
this instanceof @indexexpr and isTypeExprBottomUp(this.getChildExpr(0))
}
/** Gets the generic type expression. */
Expr getBase() { result = this.getChildExpr(0) }
/** Gets the `i`th type argument. */
Expr getTypeArgument(int i) {
i >= 0 and
result = this.getChildExpr(i + 1)
}
override predicate mayHaveOwnSideEffects() { any() }
override string toString() { result = "generic type instantiation expression" }
override string getAPrimaryQlClass() { result = "GenericTypeInstantiationExpr" }
}
/**
* A slice expression, that is, a base expression followed by slice indices.
*
* Examples:
*
* ```go
* a[1:3]
* a[1:3:5]
* a[1:]
* a[:3]
* a[:]
* ```
*/
class SliceExpr extends @sliceexpr, Expr {
/** Gets the base of this slice expression. */
Expr getBase() { result = this.getChildExpr(0) }
/** Gets the lower bound of this slice expression, if any. */
Expr getLow() { result = this.getChildExpr(1) }
/** Gets the upper bound of this slice expression, if any. */
Expr getHigh() { result = this.getChildExpr(2) }
/** Gets the maximum of this slice expression, if any. */
Expr getMax() { result = this.getChildExpr(3) }
override string toString() { result = "slice expression" }
override string getAPrimaryQlClass() { result = "SliceExpr" }
}
/**
* A type assertion expression.
*
* Examples:
*
* ```go
* x.(T)
* x.(type)
* ```
*/
class TypeAssertExpr extends @typeassertexpr, Expr {
/** Gets the base expression whose type is being asserted. */
Expr getExpr() { result = this.getChildExpr(0) }
/**
* Gets the expression representing the asserted type.
*
* Note that this is not defined when the type assertion is of the form
* `x.(type)`, as found in type switches.
*/
Expr getTypeExpr() { result = this.getChildExpr(1) }
override predicate mayHaveOwnSideEffects() { any() }
override predicate isPlatformIndependentConstant() {
this.getExpr().isPlatformIndependentConstant()
}
override string toString() { result = "type assertion" }
override string getAPrimaryQlClass() { result = "TypeAssertExpr" }
}
/**
* An expression that syntactically could either be a function call or a type
* conversion expression.
*
* In most cases, the subclasses `CallExpr` and `ConversionExpr` should be used
* instead.
*
* Examples:
*
* ```go
* f(x)
* g(a, b...)
* []byte("x")
* ```
*/
class CallOrConversionExpr extends @callorconversionexpr, Expr {
override string getAPrimaryQlClass() { result = "CallOrConversionExpr" }
}
/**
* A type conversion expression.
*
* Examples:
*
* ```go
* []byte("x")
* ```
*/
class ConversionExpr extends CallOrConversionExpr {
ConversionExpr() { isTypeExprBottomUp(this.getChildExpr(0)) }
/** Gets the type expression representing the target type of the conversion. */
Expr getTypeExpr() { result = this.getChildExpr(0) }
/** Gets the operand of the type conversion. */
Expr getOperand() { result = this.getChildExpr(1) }
override predicate isPlatformIndependentConstant() {
this.getOperand().isPlatformIndependentConstant()
}
override string toString() { result = "type conversion" }
override string getAPrimaryQlClass() { result = "ConversionExpr" }
}
/**
* A function call expression.
*
* On snapshots with incomplete type information, type conversions may be misclassified
* as function call expressions.
*
* Examples:
*
* ```go
* f(x)
* g(a, b...)
* ```
*/
class CallExpr extends CallOrConversionExpr {
CallExpr() {
exists(Expr callee | callee = this.getChildExpr(0) | not isTypeExprBottomUp(callee))
or
// only calls can have an ellipsis after their last argument
has_ellipsis(this)
}
/** Gets the expression representing the function being called. */
Expr getCalleeExpr() {
if this.getChildExpr(0) instanceof GenericFunctionInstantiationExpr
then result = this.getChildExpr(0).(GenericFunctionInstantiationExpr).getBase()
else result = this.getChildExpr(0)
}
/** Gets the `i`th argument expression of this call (0-based). */
Expr getArgument(int i) {
i >= 0 and
result = this.getChildExpr(i + 1)
}
/** Gets an argument expression of this call. */
Expr getAnArgument() { result = this.getArgument(_) }
/** Gets the number of argument expressions of this call. */
int getNumArgument() { result = count(this.getAnArgument()) }
/** Holds if this call has implicit variadic arguments. */
predicate hasImplicitVarargs() {
this.getCalleeType().isVariadic() and
not this.hasEllipsis()
}
/**
* Gets an argument with an ellipsis after it which is passed to a varargs
* parameter, as in `f(x...)`.
*
* Note that if the varargs parameter is `...T` then the type of the argument
* must be assignable to the slice type `[]T`.
*/
Expr getExplicitVarargsArgument() {
this.hasEllipsis() and
result = this.getArgument(this.getNumArgument() - 1)
}
/**
* Gets the name of the invoked function, method or variable if it can be
* determined syntactically.
*
* Note that if a variable is being called then this gets the variable name
* rather than the name of the function or method that has been assigned to
* the variable.
*/
string getCalleeName() {
exists(Expr callee | callee = this.getCalleeExpr().stripParens() |
result = callee.(Ident).getName()
or
result = callee.(SelectorExpr).getSelector().getName()
)
}
/**
* Gets the signature type of the invoked function.
*
* Note that it avoids calling `getTarget()` so that it works even when that
* predicate isn't defined, for example when calling a variable with function
* type.
*/
SignatureType getCalleeType() { result = this.getCalleeExpr().getType() }
/** Gets the declared target of this call. */
Function getTarget() { this.getCalleeExpr() = result.getAReference() }
/** Holds if this call has an ellipsis after its last argument. */
predicate hasEllipsis() { has_ellipsis(this) }
override predicate mayHaveOwnSideEffects() {
this.getTarget().mayHaveSideEffects() or
not exists(this.getTarget())
}
override string toString() {
result = "call to " + this.getCalleeName()
or
not exists(this.getCalleeName()) and
result = "function call"
}
override string getAPrimaryQlClass() { result = "CallExpr" }
}
/**
* A star expression.
*
* Examples:
*
* ```go
* *x
* ```
*/
class StarExpr extends @starexpr, Expr {
/** Gets the base expression of this star expression. */
Expr getBase() { result = this.getChildExpr(0) }
override predicate mayHaveOwnSideEffects() { any() }
override string toString() { result = "star expression" }
override string getAPrimaryQlClass() { result = "StarExpr" }
}
/**
* A key-value pair in a composite literal.
*
* Examples:
*
* ```go
* "A": 1
* ```
*/
class KeyValueExpr extends @keyvalueexpr, Expr {
/** Gets the key expression of this key-value pair. */
Expr getKey() { result = this.getChildExpr(0) }
/** Gets the value expression of this key-value pair. */
Expr getValue() { result = this.getChildExpr(1) }
/** Gets the composite literal to which this key-value pair belongs. */
CompositeLit getLiteral() { this = result.getElement(_) }
override string toString() { result = "key-value pair" }
override string getAPrimaryQlClass() { result = "KeyValueExpr" }
}
/**
* An expression representing an array type.
*
* Examples:
*
* ```go
* [5]int
* ```
*/
class ArrayTypeExpr extends @arraytypeexpr, TypeExpr {
/** Gets the length expression of this array type. */
Expr getLength() { result = this.getChildExpr(0) }
/** Gets the expression representing the element type of this array type. */
Expr getElement() { result = this.getChildExpr(1) }
override string toString() { result = "array type" }
override string getAPrimaryQlClass() { result = "ArrayTypeExpr" }
}
/**
* An expression representing a struct type.
*