@@ -80,10 +80,25 @@ private cached newtype HCBase =
8080 mk_ArrayAccess ( x , i , _)
8181 }
8282 or
83+ HC_NonmemberFunctionCall ( Function fcn , HC_Args args ) {
84+ mk_NonmemberFunctionCall ( fcn , args , _)
85+ }
86+ or
87+ HC_MemberFunctionCall ( Function trg , HC qual , HC_Args args ) {
88+ mk_MemberFunctionCall ( trg , qual , args , _)
89+ }
90+ or
8391 // Any expression that is not handled by the cases above is
8492 // given a unique number based on the expression itself.
8593 HC_Unanalyzable ( Expr e ) { not analyzableExpr ( e , _) }
8694
95+ private cached newtype HC_Args =
96+ HC_EmptyArgs ( Function fcn ) {
97+ any ( )
98+ }
99+ or HC_ArgCons ( Function fcn , HC hc , int i , HC_Args list ) {
100+ mk_ArgCons ( fcn , hc , i , list , _)
101+ }
87102/**
88103 * HC is the hash-cons of an expression. The relationship between `Expr`
89104 * and `HC` is many-to-one: every `Expr` has exactly one `HC`, but multiple
@@ -120,6 +135,8 @@ class HC extends HCBase {
120135 if this instanceof HC_UnaryOp then result = "UnaryOp" else
121136 if this instanceof HC_ArrayAccess then result = "ArrayAccess" else
122137 if this instanceof HC_Unanalyzable then result = "Unanalyzable" else
138+ if this instanceof HC_NonmemberFunctionCall then result = "NonmemberFunctionCall" else
139+ if this instanceof HC_MemberFunctionCall then result = "MemberFunctionCall" else
123140 result = "error"
124141 }
125142
@@ -329,6 +346,116 @@ private predicate mk_Deref(
329346 p = hashCons ( deref .getOperand ( ) .getFullyConverted ( ) )
330347}
331348
349+ private predicate analyzableNonmemberFunctionCall (
350+ FunctionCall fc ) {
351+ forall ( int i | exists ( fc .getArgument ( i ) ) | strictcount ( fc .getArgument ( i ) ) = 1 ) and
352+ strictcount ( fc .getTarget ( ) ) = 1 and
353+ not fc .getTarget ( ) .isMember ( )
354+ }
355+
356+ private predicate mk_NonmemberFunctionCall (
357+ Function fcn ,
358+ HC_Args args ,
359+ FunctionCall fc
360+ ) {
361+ fc .getTarget ( ) = fcn and
362+ analyzableNonmemberFunctionCall ( fc ) and
363+ (
364+ exists ( HC head , HC_Args tail |
365+ args = HC_ArgCons ( fcn , head , fc .getNumberOfArguments ( ) - 1 , tail ) and
366+ mk_ArgCons ( fcn , head , fc .getNumberOfArguments ( ) - 1 , tail , fc )
367+ )
368+ or
369+ fc .getNumberOfArguments ( ) = 0 and
370+ args = HC_EmptyArgs ( fcn )
371+ )
372+ }
373+
374+ private predicate analyzableMemberFunctionCall (
375+ FunctionCall fc ) {
376+ forall ( int i | exists ( fc .getArgument ( i ) ) | strictcount ( fc .getArgument ( i ) ) = 1 ) and
377+ strictcount ( fc .getTarget ( ) ) = 1 and
378+ strictcount ( fc .getQualifier ( ) ) = 1
379+ }
380+
381+ private predicate analyzableFunctionCall (
382+ FunctionCall fc
383+ ) {
384+ analyzableNonmemberFunctionCall ( fc )
385+ or
386+ analyzableMemberFunctionCall ( fc )
387+ }
388+
389+ private predicate mk_MemberFunctionCall (
390+ Function fcn ,
391+ HC qual ,
392+ HC_Args args ,
393+ FunctionCall fc
394+ ) {
395+ fc .getTarget ( ) = fcn and
396+ analyzableMemberFunctionCall ( fc ) and
397+ hashCons ( fc .getQualifier ( ) ) = qual and
398+ (
399+ exists ( HC head , HC_Args tail |
400+ args = HC_ArgCons ( fcn , head , fc .getNumberOfArguments ( ) - 1 , tail ) and
401+ mk_ArgCons ( fcn , head , fc .getNumberOfArguments ( ) - 1 , tail , fc )
402+ )
403+ or
404+ fc .getNumberOfArguments ( ) = 0 and
405+ args = HC_EmptyArgs ( fcn )
406+ )
407+ }
408+
409+ /*
410+ private predicate analyzableImplicitThisFunctionCall(FunctionCall fc) {
411+ forall(int i | exists(fc.getArgument(i)) | strictcount(fc.getArgument(i)) = 1) and
412+ strictcount(fc.getTarget()) = 1 and
413+ fc.getQualifier().(ThisExpr).isCompilerGenerated() and
414+ fc.getTarget().isMember()
415+ }
416+
417+ private predicate mk_ImplicitThisFunctionCall(Function fcn, Function targ, HC_Args args, FunctionCall fc) {
418+ analyzableImplicitThisFunctionCall(fc) and
419+ fc.getTarget() = targ and
420+ fc.getEnclosingFunction() = fcn and
421+ analyzableImplicitThisFunctionCall(fc) and
422+ (
423+ exists(HC head, HC_Args tail |
424+ args = HC_ArgCons(targ, head, fc.getNumberOfArguments() - 1, tail) and
425+ mk_ArgCons(targ, head, fc.getNumberOfArguments() - 1, tail, fc)
426+ )
427+ or
428+ fc.getNumberOfArguments() = 0 and
429+ args = HC_EmptyArgs(targ)
430+ )
431+ }
432+
433+ private predicate mk_ImplicitThisFunctionCall_with_qualifier(
434+ Function fcn,
435+ Function targ,
436+ HC qual,
437+ HC_Args args,
438+ FunctionCall fc) {
439+ mk_ImplicitThisFunctionCall(fcn, targ, args, fc) and
440+ qual = HC_ThisExpr(fcn)
441+ }
442+ */
443+ private predicate mk_ArgCons ( Function fcn , HC hc , int i , HC_Args list , FunctionCall fc ) {
444+ analyzableFunctionCall ( fc ) and
445+ fc .getTarget ( ) = fcn and
446+ hc = hashCons ( fc .getArgument ( i ) .getFullyConverted ( ) ) and
447+ (
448+ exists ( HC head , HC_Args tail |
449+ list = HC_ArgCons ( fcn , head , i - 1 , tail ) and
450+ mk_ArgCons ( fcn , head , i - 1 , tail , fc ) and
451+ i > 0
452+ )
453+ or
454+ i = 0 and
455+ list = HC_EmptyArgs ( fcn )
456+ )
457+ }
458+
332459/** Gets the hash-cons of expression `e`. */
333460cached HC hashCons ( Expr e ) {
334461 exists ( int val , Type t
@@ -383,6 +510,17 @@ cached HC hashCons(Expr e) {
383510 exists ( HC p
384511 | mk_Deref ( p , e ) and
385512 result = HC_Deref ( p ) )
513+ or
514+ exists ( Function fcn , HC_Args args
515+ | mk_NonmemberFunctionCall ( fcn , args , e ) and
516+ result = HC_NonmemberFunctionCall ( fcn , args )
517+ )
518+ or
519+ exists ( Function fcn , HC qual , HC_Args args
520+ | mk_MemberFunctionCall ( fcn , qual , args , e ) and
521+ result = HC_MemberFunctionCall ( fcn , qual , args )
522+ )
523+
386524 or
387525 ( not analyzableExpr ( e , _) and result = HC_Unanalyzable ( e ) )
388526}
@@ -405,5 +543,7 @@ predicate analyzableExpr(Expr e, string kind) {
405543 ( analyzableUnaryOp ( e ) and kind = "UnaryOp" ) or
406544 ( analyzableThisExpr ( e ) and kind = "ThisExpr" ) or
407545 ( analyzableArrayAccess ( e ) and kind = "ArrayAccess" ) or
408- ( analyzablePointerDereferenceExpr ( e ) and kind = "PointerDereferenceExpr" )
546+ ( analyzablePointerDereferenceExpr ( e ) and kind = "PointerDereferenceExpr" ) or
547+ ( analyzableNonmemberFunctionCall ( e ) and kind = "NonmemberFunctionCall" ) or
548+ ( analyzableMemberFunctionCall ( e ) and kind = "MemberFunctionCall" )
409549}
0 commit comments