Example #1
0
        /// <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);
        }