Пример #1
0
        private static string GetMessage(IgnoreReason reason)
        {
            string reasonSuffix = null;

            switch (reason)
            {
            case IgnoreReason.LambdaNotSupported:
                reasonSuffix = " because lambdas are not supported in Gremlin.NET (TINKERPOP-1854)";
                break;

            case IgnoreReason.TraversalTDeserializationNotSupported:
                reasonSuffix = " as deserialization of g:T on GraphSON3 is not supported";
                break;

            case IgnoreReason.PNotCreatedCorrectlyByGherkinRunner:
                reasonSuffix =
                    " because the Gherkin runner can't call methods in TraversalPredicate class (TINKERPOP-1919)";
                break;

            case IgnoreReason.NumericalValuesHaveWrongTypes:
                reasonSuffix = " because the asserts currently fail due to type mismatches (TINKERPOP-1918)";
                break;

            case IgnoreReason.PWithinWrapsArgumentsInArray:
                reasonSuffix = " because P.Within() arguments are incorrectly wrapped in an array (TINKERPOP-1920)";
                break;
            }
            return($"Scenario ignored" + reasonSuffix);
        }
Пример #2
0
        private static string GetMessage(IgnoreReason reason)
        {
            string reasonSuffix = null;

            switch (reason)
            {
            case IgnoreReason.LambdaNotSupported:
                reasonSuffix = " because lambdas are not supported in Gremlin.NET (TINKERPOP-1854)";
                break;

            case IgnoreReason.TraversalTDeserializationNotSupported:
                reasonSuffix = " as deserialization of g:T on GraphSON3 is not supported";
                break;

            case IgnoreReason.PNotCreatedCorrectlyByGherkinRunner:
                reasonSuffix =
                    " because the Gherkin runner can't call methods in TraversalPredicate class (TINKERPOP-1919)";
                break;

            case IgnoreReason.PWithinWrapsArgumentsInArray:
                reasonSuffix = " because P.Within() arguments are incorrectly wrapped in an array (TINKERPOP-1920)";
                break;

            case IgnoreReason.PNotDeserializationProblem:
                reasonSuffix = " because P.Not() cannot be deserialized by Gremlin Server (TINKERPOP-1922)";
                break;
            }
            return($"Scenario ignored" + reasonSuffix);
        }
Пример #3
0
 public override int GetHashCode()
 {
     unchecked
     {
         int hashCode = Distance;
         hashCode = (hashCode * 397) ^ Radius;
         hashCode = (hashCode * 397) ^ RadiusDistance;
         hashCode = (hashCode * 397) ^ (Name != null ? Name.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (Type != null ? Type.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (InCache != null ? InCache.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (IgnoreReason != null ? IgnoreReason.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (Weight != null ? Weight.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (IsBoss != null ? IsBoss.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (IsElite != null ? IsElite.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (IsQuestMonster != null ? IsQuestMonster.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (IsMinimapActive != null ? IsMinimapActive.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (MarkerHash != null ? MarkerHash.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (MinimapTexture != null ? MinimapTexture.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ (WeightInfo != null ? WeightInfo.GetHashCode() : 0);
         hashCode = (hashCode * 397) ^ RActorGUID;
         hashCode = (hashCode * 397) ^ ActorSNO;
         hashCode = (hashCode * 397) ^ ACDGuid;
         return(hashCode);
     }
 }
Пример #4
0
        private static string GetMessage(IgnoreReason reason)
        {
            string reasonSuffix = null;

            switch (reason)
            {
            case IgnoreReason.NoReason:
                reasonSuffix = "";
                break;
            }
            return($"Scenario ignored" + reasonSuffix);
        }
Пример #5
0
        private static string GetMessage(IgnoreReason reason)
        {
            string reasonSuffix = null;

            switch (reason)
            {
            case IgnoreReason.LambdaNotSupported:
                reasonSuffix = " because lambdas are not supported in Gremlin.NET";
                break;
            }
            return($"Scenario ignored" + reasonSuffix);
        }
        private AnalyzationCandidateResult AnalyzeAsyncCandidates(BodyFunctionDataReference functionReferenceData, IEnumerable <IMethodSymbol> asyncCandidates, bool preferCancellationToken)
        {
            var orderedCandidates = preferCancellationToken
                                ? asyncCandidates.OrderBy(o => o, MethodCancellationTokenComparer.Instance).ToList()
                                : asyncCandidates.OrderByDescending(o => o, MethodCancellationTokenComparer.Instance).ToList();

            if (orderedCandidates.Count == 0)
            {
                return(new AnalyzationCandidateResult
                {
                    AsyncCandidate = null,
                    CanBeAsync = false,
                    IgnoreBodyFunctionDataReferenceReason = IgnoreReason.NoAsyncCounterparts
                });
            }

            // More than one
            // By default we will get here when there are multiple overloads of an async function (e.g. Task.Run<T>(Func<T>, CancellationToken) and Task.Run<T>(Func<Task<T>>, CancellationToken))
            // In the Task.Run case we have to check the delegate argument if it can be async or not (the delegate argument will be processed before the invocation)
            //if (functionReferenceData.DelegateArguments == null)
            //{
            //	return new AnalyzationCandidateResult
            //	{
            //		AsyncCandidate = null,
            //		CanBeAsync = false,
            //		IgnoreBodyFunctionDataReferenceReason = IgnoreReason.Custom("Multiple async counterparts without delegate arguments.", DiagnosticSeverity.Info)
            //	};
            //}

            var validCandidates = new List <AnalyzationCandidateResult>();

            foreach (var asyncCandidate in orderedCandidates)
            {
                var result = AnalyzeAsyncCandidate(functionReferenceData, asyncCandidate, preferCancellationToken);
                if (result.AsyncCandidate != null)
                {
                    validCandidates.Add(result);
                }
            }

            if (validCandidates.Count == 0)
            {
                return(new AnalyzationCandidateResult
                {
                    AsyncCandidate = null,
                    CanBeAsync = false,
                    IgnoreBodyFunctionDataReferenceReason = IgnoreReason.Custom("No async counterparts matches delegate arguments.", DiagnosticSeverity.Info)
                });
            }

            return(validCandidates[0]);
        }
Пример #7
0
 private IMethodSymbol FindAsyncCandidate(BodyFunctionDataReference functionReferenceData, IList <IMethodSymbol> asyncCandidates)
 {
     if (asyncCandidates.Count == 0)
     {
         return(null);
     }
     if (asyncCandidates.Count == 1)
     {
         return(asyncCandidates[0]);
     }
     // More than one
     // By default we will get here when there are multiple overloads of an async function (e.g. Task.Run<T>(Func<T>, CancellationToken) and Task.Run<T>(Func<Task<T>>, CancellationToken))
     // In the Task.Run case we have to check the delegate argument if it can be asnyc or not (the delegate argument will be processed before the invocation)
     if (!functionReferenceData.DelegateArguments.Any())
     {
         functionReferenceData.Ignore(IgnoreReason.Custom("Multiple async counterparts without delegate arguments.", DiagnosticSeverity.Info));
         return(null);
     }
     foreach (var functionArgument in functionReferenceData.DelegateArguments)
     {
         var funcData = functionArgument.FunctionData;
         if (funcData != null)                 // Anonymous function as argument
         {
             if (funcData.BodyFunctionReferences.All(o => o.GetConversion() != ReferenceConversion.ToAsync))
             {
                 return(null);
             }
             CalculatePreserveReturnType(funcData);
             var validOverloads = new List <IMethodSymbol>();
             foreach (var tokenOverload in asyncCandidates)
             {
                 // Check if the return type of the delegate parameter matches with the calculated return type of the anonymous function
                 var delegateSymbol = (IMethodSymbol)tokenOverload.Parameters[functionArgument.Index].Type.GetMembers("Invoke").First();
                 if (
                     (delegateSymbol.ReturnType.IsTaskType() && !funcData.PreserveReturnType) ||
                     (!delegateSymbol.ReturnType.IsTaskType() && funcData.PreserveReturnType && !funcData.Symbol.ReturnType.IsTaskType())
                     )
                 {
                     validOverloads.Add(tokenOverload);
                 }
             }
             asyncCandidates = validOverloads;
         }
         else
         {
             // TODO
             return(null);
         }
     }
     return(asyncCandidates[0]);
 }
        private bool IgnoreIfInvalidAncestor(SyntaxNode node, SyntaxNode endNode, BodyFunctionDataReference functionReferenceData)
        {
            var currAncestor = node.Parent;

            while (!currAncestor.Equals(endNode))
            {
                if (currAncestor.IsKind(SyntaxKind.QueryExpression))
                {
                    functionReferenceData.Ignore(IgnoreReason.Custom("Cannot await async method in a query expression", DiagnosticSeverity.Info));
                    return(true);
                }
                currAncestor = currAncestor.Parent;
            }
            return(false);
        }
Пример #9
0
        private static string GetMessage(IgnoreReason reason)
        {
            string reasonSuffix = null;

            switch (reason)
            {
            case IgnoreReason.EmbeddedListAssertion:
                reasonSuffix = "This test returns an embedded list in the result and the Gherkin processor does not parse that correctly";
                break;

            case IgnoreReason.NoReason:
                reasonSuffix = "";
                break;
            }
            return($"Scenario ignored" + reasonSuffix);
        }
Пример #10
0
        private static string GetMessage(IgnoreReason reason)
        {
            string reasonSuffix = null;

            switch (reason)
            {
            case IgnoreReason.LambdaNotSupported:
                reasonSuffix = " because lambdas are not supported in Gremlin.NET";
                break;

            case IgnoreReason.TraversalTDeserializationNotSupported:
                reasonSuffix = " as deserialization of g:T on GraphSON3 is not supported";
                break;
            }
            return($"Scenario ignored" + reasonSuffix);
        }
Пример #11
0
        //public static void SetExternallyBuiltContentDirectory(string absoluteDirectory)
        //{

        //    mExternallyBuiltFileWatcher.Path = absoluteDirectory;
        //    mExternallyBuiltFileWatcher.EnableRaisingEvents = true;
        //}


        private static bool IsFileIgnored(string fileName, out IgnoreReason reason)
        {
            bool isIgnored = false;

            reason = IgnoreReason.NotIgnored;

            fileName = FlatRedBall.IO.FileManager.Standardize(fileName, "", false);

            // This block of code checks
            // if the changed file sits outside
            // of the current project.  If the file
            // is a .csproj file then we want to still
            // process it.
            if (!FileManager.IsRelative(fileName) && FileManager.GetExtension(fileName) != "csproj")
            {
                if (!FileManager.IsRelativeTo(fileName, FileManager.RelativeDirectory))
                {
                    if (ProjectManager.ContentProject == null ||
                        !FileManager.IsRelativeTo(fileName, ProjectManager.ProjectBase.GetAbsoluteContentFolder()))
                    {
                        reason    = IgnoreReason.OutsideOfProject;
                        isIgnored = true;
                    }
                }
                fileName = FileManager.MakeRelative(fileName);
            }

            if (!isIgnored && fileName.StartsWith("obj/"))
            {
                reason    = IgnoreReason.BuiltFile;
                isIgnored = true;
            }

            if (!isIgnored && IsBuiltFile(fileName))
            {
                reason    = IgnoreReason.BuiltFile;
                isIgnored = true;
            }

            if (!isIgnored && fileName.ToLower().EndsWith(".generated.cs"))
            {
                reason    = IgnoreReason.GeneratedCodeFile;
                isIgnored = true;
            }

            return(isIgnored);
        }
Пример #12
0
        //public static void SetExternallyBuiltContentDirectory(string absoluteDirectory)
        //{

        //    mExternallyBuiltFileWatcher.Path = absoluteDirectory;
        //    mExternallyBuiltFileWatcher.EnableRaisingEvents = true;
        //}


        private static bool IsFileIgnored(FilePath filePath, out IgnoreReason reason)
        {
            bool isIgnored = false;

            reason = IgnoreReason.NotIgnored;

            var projectDirectory = new FilePath(GlueState.Self.CurrentGlueProjectDirectory);
            var contentDirectory = new FilePath(GlueState.Self.ContentDirectory);
            var objFolder        = new FilePath(projectDirectory.FullPath + "obj/");
            var binFolder        = new FilePath(projectDirectory.FullPath + "bin/");

            // This block of code checks
            // if the changed file sits outside
            // of the current project.  If the file
            // is a .csproj file then we want to still
            // process it.
            if (!projectDirectory.IsRootOf(filePath) &&
                !contentDirectory.IsRootOf(filePath) &&
                filePath.Extension != "csproj")
            {
                reason    = IgnoreReason.OutsideOfProject;
                isIgnored = true;
            }

            if (!isIgnored && objFolder.IsRootOf(filePath))
            {
                reason    = IgnoreReason.BuiltFile;
                isIgnored = true;
            }

            if (!isIgnored && binFolder.IsRootOf(filePath))
            {
                reason    = IgnoreReason.BuiltFile;
                isIgnored = true;
            }

            if (!isIgnored && filePath.FullPath.ToLower().EndsWith(".generated.cs"))
            {
                reason    = IgnoreReason.GeneratedCodeFile;
                isIgnored = true;
            }

            return(isIgnored);
        }
Пример #13
0
        private static string GetMessage(IgnoreReason reason)
        {
            string reasonSuffix = null;

            switch (reason)
            {
            case IgnoreReason.TraversalTDeserializationNotSupported:
                reasonSuffix = " as deserialization of g:T on GraphSON3 is not supported";
                break;

            case IgnoreReason.NoReason:
                reasonSuffix = "";
                break;

            case IgnoreReason.ReceivedDataDoesntMatchExpected:
                reasonSuffix = " because received data from server doesn't match expected data.";
                break;
            }
            return($"Scenario ignored" + reasonSuffix);
        }
Пример #14
0
        //////////////////////////////////////////////////////////////////////////
        private string IgnoreReasonToString(IgnoreReason Reason)
        {
            switch (Reason)
            {
            case IgnoreReason.AlreadyInTable:
                return("Already in string table");

            case IgnoreReason.InIgnoreList:
                return("In ignore list");

            case IgnoreReason.IsFilename:
                return("File name");

            case IgnoreReason.KnownCodePattern:
                return("Known code pattern");

            case IgnoreReason.SelectedByUser:
                return("Removed by user");

            default:
                return("Unknown");
            }
        }
        private void AnalyzeMethodReference(DocumentData documentData, BodyFunctionDataReference refData)
        {
            var nameNode = refData.ReferenceNameNode;

            // Find the actual usage of the method
            SyntaxNode currNode = nameNode;
            var        ascend   = true;

            if (refData.ReferenceSymbol.IsPropertyAccessor())
            {
                ascend = false;
                AnalyzeAccessor(documentData, nameNode, refData);
            }
            else
            {
                currNode = nameNode.Parent;
            }

            while (ascend)
            {
                ascend = false;
                switch (currNode.Kind())
                {
                case SyntaxKind.ConditionalExpression:
                    break;

                case SyntaxKind.InvocationExpression:
                    AnalyzeInvocationExpression(documentData, (InvocationExpressionSyntax)currNode, refData);
                    break;

                case SyntaxKind.Argument:
                    AnalyzeArgumentExpression((ArgumentSyntax)currNode, nameNode, refData);
                    break;

                case SyntaxKind.AddAssignmentExpression:
                    refData.Ignore(IgnoreReason.Custom(
                                       $"Cannot attach an async method to an event (void async is not an option as cannot be awaited)", DiagnosticSeverity.Info));
                    break;

                case SyntaxKind.SubtractAssignmentExpression:
                    refData.Ignore(IgnoreReason.Custom($"Cannot detach an async method to an event", DiagnosticSeverity.Info));
                    break;

                case SyntaxKind.VariableDeclaration:
                    refData.Ignore(IgnoreReason.NotSupported($"Assigning async method to a variable is not supported"));
                    break;

                case SyntaxKind.CastExpression:
                    refData.AwaitInvocation = true;
                    ascend = true;
                    break;

                case SyntaxKind.ReturnStatement:
                    break;

                case SyntaxKind.ArrayInitializerExpression:
                case SyntaxKind.CollectionInitializerExpression:
                case SyntaxKind.ComplexElementInitializerExpression:
                    refData.Ignore(IgnoreReason.NotSupported($"Async method inside an array/collection initializer is not supported"));
                    break;

                // skip
                case SyntaxKind.VariableDeclarator:
                case SyntaxKind.EqualsValueClause:
                case SyntaxKind.SimpleMemberAccessExpression:
                case SyntaxKind.ArgumentList:
                case SyntaxKind.ObjectCreationExpression:
                case SyntaxKind.MemberBindingExpression:                         // ?.
                    ascend = true;
                    break;

                default:
                    throw new NotSupportedException(
                              $"Unknown node kind: {currNode.Kind()} at {currNode?.SyntaxTree.GetLineSpan(currNode.Span)}. Node:{Environment.NewLine}{currNode}");
                }

                if (ascend)
                {
                    currNode = currNode.Parent;
                }
            }
            refData.ReferenceNode = currNode;
            if (!refData.AwaitInvocation.HasValue)
            {
                refData.AwaitInvocation = refData.Conversion != ReferenceConversion.Ignore;
            }
        }
Пример #16
0
 public IgnoreException(IgnoreReason reason) : base(GetMessage(reason))
 {
 }
        private void PreAnalyzeFunctionData(FunctionData functionData, SemanticModel semanticModel)
        {
            var methodSymbol = functionData.Symbol;

            if (functionData.Conversion == MethodConversion.Ignore)
            {
                return;
            }

            functionData.Conversion = _configuration.GetMethodConversion(methodSymbol);
            // TODO: validate conversion
            if (functionData.Conversion == MethodConversion.Ignore)
            {
                functionData.Ignore(IgnoreReason.MethodConversion, true);
                return;
            }

            functionData.ForceAsync = functionData.Conversion.HasFlag(MethodConversion.ToAsync);
            var newType = functionData.TypeData.IsNewType;

            // Here we want to log only ignored methods that were explicitly set to async
            void IgnoreOrCopy(IgnoreReason reason)
            {
                if (newType)
                {
                    functionData.Copy();
                }
                else
                {
                    if (functionData.ForceAsync)
                    {
                        reason = reason.WithSeverity(DiagnosticSeverity.Warning);
                    }
                    functionData.Ignore(reason);
                }
            }

            if (methodSymbol.IsAsync || methodSymbol.Name.EndsWith("Async"))
            {
                IgnoreOrCopy(IgnoreReason.AlreadyAsync);
                return;
            }
            if (
                methodSymbol.MethodKind != MethodKind.Ordinary &&
                methodSymbol.MethodKind != MethodKind.ExplicitInterfaceImplementation &&
                methodSymbol.MethodKind != MethodKind.PropertyGet &&
                methodSymbol.MethodKind != MethodKind.PropertySet)
            {
                IgnoreOrCopy(IgnoreReason.NotSupported($"Unsupported method kind {methodSymbol.MethodKind}"));
                return;
            }

            if (methodSymbol.Parameters.Any(o => o.RefKind == RefKind.Out))
            {
                IgnoreOrCopy(IgnoreReason.OutParameters);
                return;
            }
            FillFunctionLocks(functionData, semanticModel);

            if (!(functionData is MethodOrAccessorData methodData))
            {
                return;
            }

            // Override user configuration if the method is set to be copied on a partial type conversion
            if (methodData.Conversion == MethodConversion.Copy && !newType)
            {
                methodData.AddDiagnostic(
                    "Method cannot be copied, when the containing type conversion is not set to be a new type. " +
                    $"Override the method conversion to '{MethodConversion.Unknown}'",
                    DiagnosticSeverity.Warning);
                methodData.Conversion = MethodConversion.Unknown;
            }

            // Check if explicitly implements external interfaces
            if (methodSymbol.MethodKind == MethodKind.ExplicitInterfaceImplementation)
            {
                foreach (var interfaceMember in methodSymbol.ExplicitInterfaceImplementations)
                {
                    // Check if the interface member has an async counterpart
                    var asyncConterparts = FillRelatedAsyncMethods(methodData, interfaceMember);
                    if (methodSymbol.ContainingAssembly.Name != interfaceMember.ContainingAssembly.Name)
                    {
                        methodData.ExternalRelatedMethods.TryAdd(interfaceMember);
                        if (!asyncConterparts.Any())
                        {
                            IgnoreOrCopy(IgnoreReason.ExplicitImplementsExternalMethodWithoutAsync(interfaceMember));
                            return;
                        }
                    }
                    else
                    {
                        methodData.ImplementedInterfaces.TryAdd(interfaceMember);
                    }
                    // For new types we need to copy all interface members
                    if (newType)
                    {
                        methodData.SoftCopy();
                    }
                }
            }

            // Check if the method is overriding an external method
            var overridenMethod = methodSymbol.OverriddenMethod;

            while (overridenMethod != null)
            {
                // Check if the member has an async counterpart that is not implemented in the current type (missing member)
                var asyncConterparts = FillRelatedAsyncMethods(methodData, overridenMethod);
                if (methodSymbol.ContainingAssembly.Name != overridenMethod.ContainingAssembly.Name)
                {
                    methodData.ExternalRelatedMethods.TryAdd(overridenMethod);
                    if (!asyncConterparts.Any())
                    {
                        IgnoreOrCopy(IgnoreReason.OverridesExternalMethodWithoutAsync(overridenMethod));
                        return;
                    }
                }
                else
                {
                    methodData.OverridenMethods.TryAdd(overridenMethod);
                }
                if (overridenMethod.OverriddenMethod != null)
                {
                    overridenMethod = overridenMethod.OverriddenMethod;
                }
                else
                {
                    break;
                }
            }
            methodData.BaseOverriddenMethod = overridenMethod;

            // Check if the method is implementing an external interface, if true skip as we cannot modify externals
            // FindImplementationForInterfaceMember will find the first implementation method starting from the deepest base class
            var type             = methodSymbol.ContainingType;
            var interfaceMembers = type.AllInterfaces
                                   .SelectMany(
                o => o.GetMembers(methodSymbol.Name)
                .Where(
                    m =>
            {
                // Find out if the method implements the interface member or an override
                // method that implements it
                var impl = type.FindImplementationForInterfaceMember(m);
                return(methodSymbol.Equals(impl) || methodData.OverridenMethods.Any(ov => ov.Equals(impl)));
            }
                    ))
                                   .OfType <IMethodSymbol>()
                                   .ToList();

            foreach (var interfaceMember in interfaceMembers)
            {
                // Check if the member has an async counterpart that is not implemented in the current type (missing member)
                var asyncConterparts = FillRelatedAsyncMethods(methodData, interfaceMember);
                if (methodSymbol.ContainingAssembly.Name != interfaceMember.ContainingAssembly.Name)
                {
                    // Check if there is an internal interface member that hides this method
                    if (interfaceMembers.Where(o => o.ContainingAssembly.Name == methodSymbol.ContainingAssembly.Name)
                        .Any(o => o.GetHiddenMethods().Any(hm => hm.Equals(interfaceMember))))
                    {
                        continue;
                    }
                    methodData.ExternalRelatedMethods.TryAdd(interfaceMember);
                    if (!asyncConterparts.Any())
                    {
                        IgnoreOrCopy(IgnoreReason.ImplementsExternalMethodWithoutAsync(interfaceMember));
                        return;
                    }
                }
                else
                {
                    methodData.ImplementedInterfaces.TryAdd(interfaceMember);
                }
                // For new types we need to copy all interface member
                if (newType)
                {
                    methodData.SoftCopy();
                }
            }

            // Verify if there is already an async counterpart for this method
            //TODO: this is not correct when generating methods with a cancellation token as here we do not know
            // if the generated method will have the cancellation token parameter or not
            var asyncCounterparts = GetAsyncCounterparts(methodSymbol.OriginalDefinition, _preAnalyzeSearchOptions).ToList();

            if (asyncCounterparts.Any())
            {
                if (!_preAnalyzeSearchOptions.HasFlag(AsyncCounterpartsSearchOptions.HasCancellationToken) && asyncCounterparts.Count > 1)
                {
                    throw new InvalidOperationException($"Method {methodSymbol} has more than one async counterpart");
                }
                // We shall get a maximum of two async counterparts when the HasCancellationToken flag is used
                if (_preAnalyzeSearchOptions.HasFlag(AsyncCounterpartsSearchOptions.HasCancellationToken) && asyncCounterparts.Count > 2)
                {
                    throw new InvalidOperationException($"Method {methodSymbol} has more than two async counterparts");
                }

                foreach (var asyncCounterpart in asyncCounterparts)
                {
                    // Check if the async counterpart has a cancellation token
                    if (asyncCounterpart.Parameters.Length > methodSymbol.Parameters.Length)
                    {
                        methodData.AsyncCounterpartWithTokenSymbol = asyncCounterpart;
                    }
                    else
                    {
                        methodData.AsyncCounterpartSymbol = asyncCounterpart;
                    }

                    methodData.IgnoreAsyncCounterpart = _configuration.IgnoreAsyncCounterpartsPredicates.Any(p => p(asyncCounterpart));
                }
                // TODO: define a better logic
                // We should not ignore if none of the async counterparts is in the sync method type.
                if (asyncCounterparts.Any(o => o.ContainingType.Equals(methodSymbol.ContainingType))

                    /*(_configuration.UseCancellationTokens && asyncCounterparts.Count == 2) ||
                     * (!_configuration.UseCancellationTokens && asyncCounterparts.Count == 1)*/
                    )
                {
                    IgnoreOrCopy(IgnoreReason.AsyncCounterpartExists);
                    methodData.CancellationTokenRequired = methodData.AsyncCounterpartWithTokenSymbol != null;
                    return;
                }
            }

            // Create an override async method if any of the related async methods is virtual or abstract
            // We need to do this here so that the method body will get scanned for async counterparts
            if (methodData.RelatedAsyncMethods.Any(o => o.IsVirtual || o.IsAbstract) &&
                _configuration.CanScanForMissingAsyncMembers?.Invoke(methodData.TypeData.Symbol) == true)
            {
                if (!methodData.Conversion.HasAnyFlag(MethodConversion.ToAsync, MethodConversion.Smart))
                {
                    methodData.Smart();
                }
                if (newType)
                {
                    methodData.SoftCopy();
                }

                // We have to generate the cancellation token parameter if the async member has more parameters that the sync counterpart
                var asyncMember = methodData.RelatedAsyncMethods
                                  .Where(o => o.IsVirtual || o.IsAbstract)
                                  .FirstOrDefault(o => o.Parameters.Length > methodData.Symbol.Parameters.Length);
                if (asyncMember != null)
                {
                    methodData.CancellationTokenRequired = true;
                    // We suppose that the cancellation token is the last parameter
                    methodData.MethodCancellationToken = asyncMember.Parameters.Last().HasExplicitDefaultValue
                                                ? MethodCancellationToken.Optional
                                                : MethodCancellationToken.Required;
                }
            }
        }
Пример #18
0
        //public static void SetExternallyBuiltContentDirectory(string absoluteDirectory)
        //{

        //    mExternallyBuiltFileWatcher.Path = absoluteDirectory;
        //    mExternallyBuiltFileWatcher.EnableRaisingEvents = true;
        //}


        private static bool IsFileIgnored(string fileName, out IgnoreReason reason)
        {
            bool isIgnored = false;
            reason = IgnoreReason.NotIgnored;

            fileName = FlatRedBall.IO.FileManager.Standardize(fileName, "", false);

            // This block of code checks
            // if the changed file sits outside
            // of the current project.  If the file
            // is a .csproj file then we want to still
            // process it.
            if (!FileManager.IsRelative(fileName) && FileManager.GetExtension(fileName) != "csproj")
            {
                if (!FileManager.IsRelativeTo(fileName, FileManager.RelativeDirectory))
                {
                    if (ProjectManager.ContentProject == null ||
                        !FileManager.IsRelativeTo(fileName, ProjectManager.ContentProject.Directory))
                    {
                        reason = IgnoreReason.OutsideOfProject;
                        isIgnored = true;
                    }

                }
                fileName = FileManager.MakeRelative(fileName);
            }

            if(!isIgnored && fileName.StartsWith("obj/"))
            {
                reason = IgnoreReason.BuiltFile;
                isIgnored = true;
            }

            if (!isIgnored && IsBuiltFile(fileName))
            {
                reason = IgnoreReason.BuiltFile;
                isIgnored = true;
            }

            if (!isIgnored && fileName.ToLower().EndsWith(".generated.cs"))
            {
                reason = IgnoreReason.GeneratedCodeFile;
                isIgnored = true;
            }

            return isIgnored;                
        }
        private AnalyzationCandidateResult AnalyzeAsyncCandidate(BodyFunctionDataReference functionReferenceData,
                                                                 IMethodSymbol asyncCandidate, bool useCancellationToken)
        {
            var canBeAsync           = true;
            var asnycDelegateIndexes = functionReferenceData.ReferenceSymbol.GetAsyncDelegateArgumentIndexes(asyncCandidate);

            if (asnycDelegateIndexes != null)
            {
                if (asnycDelegateIndexes.Count == 0 && functionReferenceData.DelegateArguments != null)
                {
                    return(new AnalyzationCandidateResult
                    {
                        AsyncCandidate = asyncCandidate,
                        CanBeAsync = true,
                        IgnoreDelegateArgumentsReason =
                            IgnoreReason.Custom("Argument is not async.", DiagnosticSeverity.Hidden)
                    });
                }
                if (asnycDelegateIndexes.Count > 0 && functionReferenceData.DelegateArguments == null)
                {
                    return(new AnalyzationCandidateResult
                    {
                        AsyncCandidate = null,
                        CanBeAsync = false,
                        IgnoreBodyFunctionDataReferenceReason =
                            IgnoreReason.Custom("Delegate argument is not async.", DiagnosticSeverity.Hidden)
                    });
                }
            }

            if (functionReferenceData.DelegateArguments == null)
            {
                return(new AnalyzationCandidateResult
                {
                    AsyncCandidate = asyncCandidate,
                    CanBeAsync = true
                });
            }

            if (asnycDelegateIndexes != null)
            {
                var delegateIndexes = functionReferenceData.DelegateArguments.Select(o => o.Index).ToList();
                if (delegateIndexes.Count != asnycDelegateIndexes.Count ||
                    asnycDelegateIndexes.Any(o => !delegateIndexes.Contains(o)))
                {
                    return(new AnalyzationCandidateResult
                    {
                        AsyncCandidate = null,
                        CanBeAsync = false,
                        IgnoreBodyFunctionDataReferenceReason =
                            IgnoreReason.Custom("Delegate arguments do not match with the async counterpart.", DiagnosticSeverity.Hidden)
                    });
                }
            }

            foreach (var functionArgument in functionReferenceData.DelegateArguments)
            {
                var funcData = functionArgument.FunctionData;

                if (funcData == null)
                {
                    var bodyRef = functionArgument.FunctionReference;
                    funcData = bodyRef.ReferenceFunctionData;

                    //if (!result.CanBeAsync)
                    //{
                    //	return new AnalyzationCandidateResult
                    //	{
                    //		AsyncCandidate = null,
                    //		CanBeAsync = false,
                    //		IgnoreBodyFunctionDataReferenceReason =
                    //			IgnoreReason.Custom("Delegate argument cannot be async.", DiagnosticSeverity.Hidden)
                    //	};
                    //}

                    if (funcData == null)
                    {
                        var result = AnalyzeAsyncCandidates(bodyRef, bodyRef.ReferenceAsyncSymbols.ToList(), useCancellationToken);
                        if (result.AsyncCandidate != null && functionArgument.Index < asyncCandidate.Parameters.Length)
                        {
                            var delegateSymbol = (IMethodSymbol)asyncCandidate.Parameters[functionArgument.Index].Type.GetMembers("Invoke").First();
                            if (!delegateSymbol.MatchesDefinition(result.AsyncCandidate, true))
                            {
                                return(new AnalyzationCandidateResult
                                {
                                    AsyncCandidate = null,
                                    CanBeAsync = false,
                                    IgnoreBodyFunctionDataReferenceReason =
                                        IgnoreReason.Custom("Delegate argument async counterpart does not match.", DiagnosticSeverity.Hidden)
                                });
                            }
                        }

                        continue;
                    }
                }
                if (funcData.BodyFunctionReferences.All(o => o.GetConversion() == ReferenceConversion.Ignore))
                {
                    return(new AnalyzationCandidateResult
                    {
                        AsyncCandidate = null,
                        CanBeAsync = false,
                        IgnoreBodyFunctionDataReferenceReason =
                            IgnoreReason.Custom("The delegate argument does not have any async invocation.", DiagnosticSeverity.Hidden)
                    });
                }

                canBeAsync &= funcData.BodyFunctionReferences.Any(o => o.GetConversion() == ReferenceConversion.ToAsync);
                //if (funcData.Symbol.MethodKind != MethodKind.AnonymousFunction)
                //{
                //	CalculatePreserveReturnType(funcData);
                //}

                //// Check if the return type of the delegate parameter matches with the calculated return type of the anonymous function
                //if (
                //	(delegateSymbol.ReturnType.SupportsTaskType() && !funcData.PreserveReturnType) ||
                //	(!delegateSymbol.ReturnType.SupportsTaskType() && funcData.PreserveReturnType && !funcData.Symbol.ReturnType.SupportsTaskType())
                //)
                //{
                //	continue;
                //}

                //return new AnalyzationCandidateResult
                //{
                //	AsyncCandidate = null,
                //	CanBeAsync = false,
                //	IgnoreBodyFunctionDataReferenceReason =
                //		IgnoreReason.Custom("Return type of the delegate argument does not match.", DiagnosticSeverity.Hidden)
                //};
            }

            return(new AnalyzationCandidateResult
            {
                AsyncCandidate = asyncCandidate,
                CanBeAsync = canBeAsync
            });
        }
        private void AnalyzeInvocationExpression(DocumentData documentData, InvocationExpressionSyntax node, BodyFunctionDataReference functionReferenceData)
        {
            var functionData = functionReferenceData.Data;
            var methodSymbol = functionReferenceData.ReferenceSymbol;
            var functionNode = functionData.GetNode();

            if (IgnoreIfInvalidAncestor(node, functionNode, functionReferenceData))
            {
                return;
            }

            // If the invocation returns a Task then we need to analyze it further to see how the Task is handled
            if (methodSymbol.ReturnType.IsTaskType())
            {
                var retrunType   = (INamedTypeSymbol)methodSymbol.ReturnType;
                var canBeAwaited = false;
                var currNode     = node.Parent;
                while (true)
                {
                    var memberExpression = currNode as MemberAccessExpressionSyntax;
                    if (memberExpression == null)
                    {
                        break;
                    }
                    var memberName = memberExpression.Name.ToString();
                    if (retrunType.IsGenericType && memberName == "Result")
                    {
                        canBeAwaited = true;
                        break;
                    }
                    if (memberName == "ConfigureAwait")
                    {
                        var invocationNode = currNode.Parent as InvocationExpressionSyntax;
                        if (invocationNode != null)
                        {
                            functionReferenceData.ConfigureAwaitParameter = invocationNode.ArgumentList.Arguments.First().Expression;
                            currNode = invocationNode.Parent;
                            continue;
                        }
                        break;
                    }
                    if (memberName == "GetAwaiter")
                    {
                        var invocationNode = currNode.Parent as InvocationExpressionSyntax;
                        if (invocationNode != null)
                        {
                            currNode = invocationNode.Parent;
                            continue;
                        }
                        break;
                    }
                    if (_taskResultMethods.Contains(memberName))
                    {
                        var invocationNode = currNode.Parent as InvocationExpressionSyntax;
                        if (invocationNode != null)
                        {
                            canBeAwaited = true;
                        }
                    }
                    break;
                }
                if (!canBeAwaited)
                {
                    functionReferenceData.AwaitInvocation = false;
                    functionReferenceData.AddDiagnostic("Cannot await invocation that returns a Task without being synchronously awaited", DiagnosticSeverity.Info);
                }
                else
                {
                    functionReferenceData.SynchronouslyAwaited = true;
                }
            }
            if (node.Expression is SimpleNameSyntax)
            {
                functionReferenceData.InvokedFromType = functionData.Symbol.ContainingType;
            }
            else if (node.Expression is MemberAccessExpressionSyntax memberAccessExpression)
            {
                functionReferenceData.InvokedFromType = documentData.SemanticModel.GetTypeInfo(memberAccessExpression.Expression).Type;
            }

            FindAsyncCounterparts(functionReferenceData);

            var delegateParams = methodSymbol.Parameters.Select(o => o.Type.TypeKind == TypeKind.Delegate).ToList();

            for (var i = 0; i < node.ArgumentList.Arguments.Count; i++)
            {
                var argument           = node.ArgumentList.Arguments[i];
                var argumentExpression = argument.Expression;
                // We have to process anonymous funcions as they will not be analyzed as arguments
                if (argumentExpression.IsFunction())
                {
                    var anonFunction = (AnonymousFunctionData)functionData.ChildFunctions[argumentExpression];
                    functionReferenceData.AddDelegateArgument(new DelegateArgumentData(anonFunction, i));
                    anonFunction.ArgumentOfFunctionInvocation = functionReferenceData;
                    continue;
                }
                if (argumentExpression.IsKind(SyntaxKind.IdentifierName) ||
                    argumentExpression.IsKind(SyntaxKind.SimpleMemberAccessExpression))
                {
                    var argRefFunction = functionData.BodyFunctionReferences.FirstOrDefault(o => argument.Equals(o.ReferenceNode));
                    if (argRefFunction == null)
                    {
                        // Ignore only if the async argument does not match
                        // TODO: internal methods, unify with CalculateFunctionArguments
                        if (functionReferenceData.ReferenceFunctionData == null && delegateParams[i])                         // If the parameter is a delegate check the symbol of the argument
                        {
                            var argSymbol = documentData.SemanticModel.GetSymbolInfo(argumentExpression).Symbol;
                            if (argSymbol is ILocalSymbol arglocalSymbol)
                            {
                                // TODO: local arguments
                                functionReferenceData.Ignore(IgnoreReason.NotSupported("Local delegate arguments are currently not supported"));
                                return;
                            }
                            if (argSymbol is IMethodSymbol argMethodSymbol)
                            {
                                // TODO: support custom async counterparts that have different parameters
                                // If the invocation has at least one argument that does not fit into any async counterparts we have to ignore it
                                if (functionReferenceData.ReferenceAsyncSymbols
                                    .Where(o => o.Parameters.Length >= methodSymbol.Parameters.Length)                                     // The async counterpart may have less parameters. e.g. Parallel.For -> Task.WhenAll
                                    .All(o => !((IMethodSymbol)o.Parameters[i].Type.GetMembers("Invoke").First()).ReturnType.Equals(argMethodSymbol.ReturnType)))
                                {
                                    functionReferenceData.Ignore(IgnoreReason.Custom("The delegate argument does not fit to any async counterparts", DiagnosticSeverity.Hidden));
                                    return;
                                }
                            }
                        }
                        continue;
                    }
                    functionReferenceData.AddDelegateArgument(new DelegateArgumentData(argRefFunction, i));
                    argRefFunction.ArgumentOfFunctionInvocation = functionReferenceData;
                }
            }

            SetAsyncCounterpart(functionReferenceData);

            CalculateLastInvocation(node, functionReferenceData);

            foreach (var analyzer in _configuration.InvocationExpressionAnalyzers)
            {
                analyzer.AnalyzeInvocationExpression(node, functionReferenceData, documentData.SemanticModel);
            }

            PropagateCancellationToken(functionReferenceData);
        }
 //////////////////////////////////////////////////////////////////////////
 private string IgnoreReasonToString(IgnoreReason Reason)
 {
     switch (Reason)
     {
         case IgnoreReason.AlreadyInTable:
             return "Already in string table";
         case IgnoreReason.InIgnoreList:
             return "In ignore list";
         case IgnoreReason.IsFilename:
             return "File name";
         case IgnoreReason.KnownCodePattern:
             return "Known code pattern";
         case IgnoreReason.SelectedByUser:
             return "Removed by user";
         default:
             return "Unknown";
     }
 }