/// <summary> /// /// </summary> /// <param name="functionFullName">should be "[Addr].FunctionSig"</param> /// <param name="functionTemplate"></param> /// <param name="contractAddr"></param> /// <param name="contractReferences"></param> /// <returns></returns> /// <exception cref="InvalidOperationException"></exception> /// <exception cref="FunctionMetadataException"></exception> private async Task <FunctionMetadata> GetMetadataForNewFunction(string functionFullName, FunctionMetadataTemplate functionTemplate, Address contractAddr, Dictionary <string, Address> contractReferences, Dictionary <string, FunctionMetadata> localMetadataMap) { var resourceSet = new HashSet <Resource>(functionTemplate.LocalResourceSet.Select(resource => { var resName = Replacement.ReplaceValueIntoReplacement(resource.Name, Replacement.This, contractAddr.GetFormatted()); return(new Resource(resName, resource.DataAccessMode)); })); var callingSet = new HashSet <string>(); foreach (var calledFunc in functionTemplate.CallingSet ?? Enumerable.Empty <string>()) { if (!Replacement.TryGetReplacementWithIndex(calledFunc, 0, out var locationReplacement)) { throw new FunctionMetadataException("not valid template in calling set of function " + functionFullName + " because the calling function" + calledFunc + "have no location replacement (${this} or ${[calling contract name]})"); } //just add foreign resource into set because local resources are already recursively analyzed if (locationReplacement.Equals(Replacement.This)) { var replacedCalledFunc = Replacement.ReplaceValueIntoReplacement(calledFunc, Replacement.This, contractAddr.GetFormatted()); if (!localMetadataMap.TryGetValue(replacedCalledFunc, out var localCalledFuncMetadata)) { throw new FunctionMetadataException("There are no local function " + replacedCalledFunc + " in the given local function map, consider wrong reference cause wrong topological order"); } resourceSet.UnionWith(localCalledFuncMetadata.FullResourceSet); callingSet.Add(replacedCalledFunc); } else { if (!contractReferences.TryGetValue(Replacement.Value(locationReplacement), out var referenceAddr)) { throw new FunctionMetadataException("There are no member reference " + Replacement.Value(locationReplacement) + " in the given contractReferences map"); } var replacedCalledFunc = Replacement.ReplaceValueIntoReplacement(calledFunc, locationReplacement, referenceAddr.GetFormatted()); var metadataOfCalledFunc = await GetFunctionMetadata(replacedCalledFunc); //could throw exception resourceSet.UnionWith(metadataOfCalledFunc.FullResourceSet); callingSet.Add(replacedCalledFunc); } } var metadata = new FunctionMetadata(callingSet, resourceSet); return(metadata); }