protected override void VisitRoutineCall(BoundRoutineCall x) { var invocation = (IInvocationExpression)x; if (invocation.TargetMethod != null) { if (!invocation.TargetMethod.IsImplicitlyDeclared || invocation.TargetMethod is IErrorMethodSymbol) { Span span; if (x.PhpSyntax is FunctionCall) { span = ((FunctionCall)x.PhpSyntax).NameSpan; _result.Add(new SymbolStat(_tctx, span, x, invocation.TargetMethod)); } } } // base.VisitRoutineCall(x); }
public bool EnqueueRoutine(IPhpRoutineSymbol routine, T caller, BoundRoutineCall callExpression) { Contract.ThrowIfNull(routine); if (routine.ControlFlowGraph == null) { var routine2 = routine is SynthesizedMethodSymbol sr ? sr.ForwardedCall : routine.OriginalDefinition as IPhpRoutineSymbol; if (routine2 != null && !ReferenceEquals(routine, routine2)) { return(EnqueueRoutine(routine2, caller, callExpression)); } // library (sourceless) function return(false); } var sourceRoutine = (SourceRoutineSymbol)routine; if (sourceRoutine.SyntaxReturnType != null) { // we don't have to wait for return type, // nor reanalyse itself when routine analyses return(false); } _callGraph.AddEdge(caller.FlowState.Routine, sourceRoutine, new CallSite(caller, callExpression)); // ensure caller is subscribed to routine's ExitBlock ((ExitBlock)routine.ControlFlowGraph.Exit).Subscribe(caller); // TODO: check if routine has to be reanalyzed => enqueue routine's StartBlock // Return whether the routine exit block will certainly be analysed in the future return(!sourceRoutine.IsReturnAnalysed); }
protected override object VisitRoutineCall(BoundRoutineCall x) { // It must be updated in the visits of non-abstract subclassess return(x); }
public CallSite(BoundBlock block, BoundRoutineCall callExpression) { Block = block; CallExpression = callExpression; }