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); }
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); }
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); } }
private static string GetMessage(IgnoreReason reason) { string reasonSuffix = null; switch (reason) { case IgnoreReason.NoReason: reasonSuffix = ""; break; } return($"Scenario ignored" + reasonSuffix); }
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]); }
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); }
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); }
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); }
//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); }
//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); }
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); }
////////////////////////////////////////////////////////////////////////// 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; } }
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; } } }
//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"; } }