private bool TypeHasWeakIdentity(ITypeSymbol type, SemanticModel model) { switch (type.TypeKind) { case TypeKind.ArrayType: var arrayType = type as IArrayTypeSymbol; return arrayType != null && arrayType.ElementType.IsPrimitiveType(); case TypeKind.Class: case TypeKind.TypeParameter: Compilation compilation = model.Compilation; INamedTypeSymbol marshalByRefObjectTypeSymbol = compilation.GetTypeByMetadataName("System.MarshalByRefObject"); INamedTypeSymbol executionEngineExceptionTypeSymbol = compilation.GetTypeByMetadataName("System.ExecutionEngineException"); INamedTypeSymbol outOfMemoryExceptionTypeSymbol = compilation.GetTypeByMetadataName("System.OutOfMemoryException"); INamedTypeSymbol stackOverflowExceptionTypeSymbol = compilation.GetTypeByMetadataName("System.StackOverflowException"); INamedTypeSymbol memberInfoTypeSymbol = compilation.GetTypeByMetadataName("System.Reflection.MemberInfo"); INamedTypeSymbol parameterInfoTypeSymbol = compilation.GetTypeByMetadataName("System.Reflection.ParameterInfo"); INamedTypeSymbol threadTypeSymbol = compilation.GetTypeByMetadataName("System.Threading.Thread"); return type.SpecialType == SpecialType.System_String || type.Equals(executionEngineExceptionTypeSymbol) || type.Equals(outOfMemoryExceptionTypeSymbol) || type.Equals(stackOverflowExceptionTypeSymbol) || type.Inherits(marshalByRefObjectTypeSymbol) || type.Inherits(memberInfoTypeSymbol) || type.Inherits(parameterInfoTypeSymbol) || type.Inherits(threadTypeSymbol); // What about struct types? default: return false; } }
private static bool HasPublicWritableIndexer( ExpressionSyntax expression, ObjectCreationExpressionSyntax objectCreationExpression, SemanticModel semanticModel, CancellationToken cancellationToken) { var typeSymbol = semanticModel.GetSymbol(objectCreationExpression.Type, cancellationToken) as ITypeSymbol; if (typeSymbol != null) { foreach (ISymbol member in typeSymbol.GetMembers("this[]")) { if (member.IsPublic() && !member.IsStatic && member.IsProperty()) { var propertySymbol = (IPropertySymbol)member; if (!propertySymbol.IsReadOnly) { ImmutableArray <IParameterSymbol> parameters = propertySymbol.Parameters; if (parameters.Length == 1) { ITypeSymbol expressionSymbol = semanticModel.GetTypeInfo(expression, cancellationToken).ConvertedType; return(expressionSymbol?.Equals(propertySymbol.Parameters[0].Type) == true); } } } } } return(false); }
private static void AnalyzeObjectCreationExpression(SyntaxNodeAnalysisContext context, INamedTypeSymbol dateTimeSymbol) { var objectCreationSyntax = (ObjectCreationExpressionSyntax)context.Node; ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(objectCreationSyntax, context.CancellationToken); if (typeSymbol?.Equals(dateTimeSymbol) != true) { return; } var dateTimeKindArgument = objectCreationSyntax.ArgumentList.Arguments.FirstOrDefault(e => (e is ArgumentSyntax argumentSyntax) && (argumentSyntax.Expression is MemberAccessExpressionSyntax memberSyntax) && (memberSyntax.Expression is IdentifierNameSyntax idSyntax) && idSyntax.Identifier.ValueText == DATETIMEKIND); if (dateTimeKindArgument is null) { context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation())); } else if (dateTimeKindArgument.Expression.TryGetInferredMemberName() != UTC) { context.ReportDiagnostic(Diagnostic.Create(Rule, context.Node.GetLocation())); } }
private static bool HasPublicAddMethod( ExpressionSyntax expression, ObjectCreationExpressionSyntax objectCreationExpression, SemanticModel semanticModel, CancellationToken cancellationToken) { var typeSymbol = semanticModel.GetSymbol(objectCreationExpression.Type, cancellationToken) as ITypeSymbol; if (typeSymbol != null) { foreach (IMethodSymbol methodSymbol in typeSymbol.GetMethods("Add")) { if (methodSymbol.IsPublic() && !methodSymbol.IsStatic) { ImmutableArray <IParameterSymbol> parameters = methodSymbol.Parameters; if (parameters.Length == 1) { ITypeSymbol expressionSymbol = semanticModel.GetTypeInfo(expression, cancellationToken).ConvertedType; return(expressionSymbol?.Equals(parameters[0].Type) == true); } } } } return(false); }
private void AnalyzeMethodInvocation(SyntaxNodeAnalysisContext context) { var invocation = (InvocationExpressionSyntax)context.Node; var symbol = context.SemanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; if (symbol != null && FormatHelper.IsFormattableCall(symbol, context.SemanticModel)) { var parsedFormat = FormatHelper.ParseFormatMethodInvocation(invocation, symbol, context.SemanticModel); if (!parsedFormat.IsValid) { context.ReportDiagnostic(Diagnostic.Create(InvalidFormatRule, parsedFormat.FormatArgument.GetLocation())); } else { // Special corner case: if param args is an expression that provides object or object[] // then giving up the analysis! int actualArgumentsLength = parsedFormat.Args.Length; if (parsedFormat.Args.Length == 1) { ITypeSymbol expressionType = GetExpressionType(parsedFormat.Args[0], context.SemanticModel); if (expressionType?.Equals(context.SemanticModel.GetClrType(typeof(object))) == true || IsArrayOfObjects(expressionType, context.SemanticModel)) { // Giving up all the checks! Can't deal with them! return; } } // Checking for non-existed indices in a format string var missedArguments = parsedFormat.UsedIndices.Where(i => i < 0 || i >= actualArgumentsLength).ToList(); if (missedArguments.Count != 0) { context.ReportDiagnostic(Diagnostic .Create( NonExistingIndexRule, parsedFormat.FormatArgument.GetLocation(), string.Join(", ", missedArguments))); } // TODO: unused parameters should have warnings on the parameters themselves not on the string format! var excessiveArguments = Enumerable.Range(0, actualArgumentsLength) .Where(i => !parsedFormat.UsedIndices.Contains(i)) .Select(i => parsedFormat.Args[i]) .ToList(); foreach (var excessiveArg in excessiveArguments) { context.ReportDiagnostic( Diagnostic.Create( ExcessiveArgumentRule, excessiveArg.GetLocation(), excessiveArg)); } } } }
protected static bool IsPropertyAccessSomeObviousTypeCase(SyntaxNodeAnalysisContext nodeContext, ExpressionSyntax initializerExpression, ITypeSymbol variableType) { var simpleMemberAccess = initializerExpression as MemberAccessExpressionSyntax; if (simpleMemberAccess != null) { var propertyType = nodeContext.SemanticModel.GetTypeInfo(simpleMemberAccess, nodeContext.CancellationToken).Type; return propertyType != null && variableType.Equals(propertyType); } return false; }
static bool CheckCuriouslyRecurringTemplatePattern(ITypeSymbol containingType, ITypeSymbol type) { if (containingType.Equals(type)) return true; var nt = containingType as INamedTypeSymbol; if (nt == null) return false; foreach (var typeArg in nt.TypeArguments) { if (CheckCuriouslyRecurringTemplatePattern(typeArg, type)) return true; } return false; }
internal static bool IsSameType(this ITypeSymbol first, ITypeSymbol other) { if (ReferenceEquals(first, other) || first?.Equals(other) == true) { return(true); } if (first is ITypeParameterSymbol firstParameter && other is ITypeParameterSymbol otherParameter) { return(firstParameter.MetadataName == otherParameter.MetadataName && firstParameter.ContainingSymbol.Equals(otherParameter.ContainingSymbol)); } return(first is INamedTypeSymbol firstNamed && other is INamedTypeSymbol otherNamed && IsSameType(firstNamed, otherNamed)); }
public static void AnalyzeObjectCreationExpression(SyntaxNodeAnalysisContext context, INamedTypeSymbol eventArgsSymbol) { if (context.Node.SpanContainsDirectives()) { return; } var objectCreation = (ObjectCreationExpressionSyntax)context.Node; if (objectCreation.ArgumentList?.Arguments.Count == 0 && objectCreation.Initializer == null) { ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(objectCreation, context.CancellationToken); if (typeSymbol?.Equals(eventArgsSymbol) == true) { context.ReportDiagnostic(DiagnosticDescriptors.UseEventArgsEmpty, objectCreation); } } }
public static void AnalyzeCatchClause(SyntaxNodeAnalysisContext context, ITypeSymbol exceptionSymbol) { if (context.Node.ContainsDiagnostics) { return; } var catchClause = (CatchClauseSyntax)context.Node; if (catchClause.Filter != null) { return; } if (catchClause.Block?.Statements.Any() != false) { return; } TypeSyntax type = catchClause.Declaration?.Type; if (type == null) { return; } ITypeSymbol typeSymbol = context.SemanticModel.GetTypeSymbol(type, context.CancellationToken); if (typeSymbol?.Equals(exceptionSymbol) != true) { return; } context.ReportDiagnostic( DiagnosticDescriptors.AvoidEmptyCatchClauseThatCatchesSystemException, catchClause.CatchKeyword); }
protected static bool IsTaskLike( ITypeSymbol returnType, ITypeSymbol taskType, INamedTypeSymbol taskOfTType) { if (returnType.Equals(taskType)) { return true; } if (returnType.OriginalDefinition.Equals(taskOfTType)) { return true; } if (returnType.IsErrorType() && returnType.Name.Equals("Task")) { return true; } return false; }
public static TypeAnalysisFlags AnalyzeType( VariableDeclarationSyntax variableDeclaration, SemanticModel semanticModel, CancellationToken cancellationToken = default(CancellationToken)) { if (variableDeclaration == null) { throw new ArgumentNullException(nameof(variableDeclaration)); } if (semanticModel == null) { throw new ArgumentNullException(nameof(semanticModel)); } TypeSyntax type = variableDeclaration.Type; if (type != null) { SeparatedSyntaxList <VariableDeclaratorSyntax> variables = variableDeclaration.Variables; if (variables.Count > 0 && !variableDeclaration.IsParentKind(SyntaxKind.FieldDeclaration, SyntaxKind.EventFieldDeclaration)) { ExpressionSyntax expression = variables[0].Initializer?.Value; if (expression != null) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type, cancellationToken); if (typeSymbol?.IsErrorType() == false) { var flags = TypeAnalysisFlags.None; if (typeSymbol.IsDynamicType()) { flags = TypeAnalysisFlags.Dynamic; } else { flags = TypeAnalysisFlags.ValidSymbol; if (type.IsVar) { flags |= TypeAnalysisFlags.Implicit; if (typeSymbol.SupportsExplicitDeclaration()) { flags |= TypeAnalysisFlags.SupportsExplicit; } } else { flags |= TypeAnalysisFlags.Explicit; if (variables.Count == 1 && !IsLocalConstDeclaration(variableDeclaration) && !expression.IsKind(SyntaxKind.NullLiteralExpression) && typeSymbol.Equals(semanticModel.GetTypeSymbol(expression, cancellationToken))) { flags |= TypeAnalysisFlags.SupportsImplicit; } } if (IsTypeObvious(expression, semanticModel, cancellationToken)) { flags |= TypeAnalysisFlags.TypeObvious; } } return(flags); } } } } return(TypeAnalysisFlags.None); }
private static bool Inherits(ITypeSymbol symbol, ITypeSymbol baseType) { Debug.Assert(baseType.Equals(baseType.OriginalDefinition)); return(symbol?.OriginalDefinition.Inherits(baseType) ?? false); }
public static async Task ComputeRefactoringAsync(RefactoringContext context, EventFieldDeclarationSyntax eventFieldDeclaration) { if (eventFieldDeclaration.IsParentKind(SyntaxKind.InterfaceDeclaration)) { return; } VariableDeclarationSyntax variableDeclaration = eventFieldDeclaration.Declaration; if (variableDeclaration == null) { return; } SemanticModel semanticModel = null; foreach (VariableDeclaratorSyntax variableDeclarator in variableDeclaration.Variables) { if (!context.Span.IsContainedInSpanOrBetweenSpans(variableDeclarator.Identifier)) { continue; } semanticModel = semanticModel ?? await context.GetSemanticModelAsync().ConfigureAwait(false); var eventSymbol = semanticModel.GetDeclaredSymbol(variableDeclarator, context.CancellationToken) as IEventSymbol; if (eventSymbol?.IsStatic != false) { continue; } INamedTypeSymbol containingType = eventSymbol.ContainingType; if (containingType == null) { return; } if (!(eventSymbol.Type is INamedTypeSymbol eventHandlerType)) { continue; } ITypeSymbol eventArgsSymbol = GetEventArgsSymbol(eventHandlerType, semanticModel); if (eventArgsSymbol == null) { continue; } string methodName = "On" + eventSymbol.Name; if (containingType.ContainsMember <IMethodSymbol>( $"On{eventSymbol.Name}", methodSymbol => eventArgsSymbol.Equals(methodSymbol.Parameters.SingleOrDefault(shouldThrow: false)?.Type))) { continue; } methodName = NameGenerator.Default.EnsureUniqueName(methodName, containingType.GetMembers()); context.RegisterRefactoring( $"Generate '{methodName}' method", cancellationToken => { return(RefactorAsync( context.Document, eventFieldDeclaration, eventSymbol, eventArgsSymbol, context.SupportsCSharp6, cancellationToken)); }, RefactoringIdentifiers.GenerateEventInvokingMethod); } }
/// <summary> /// Classifies the type of the <paramref name="expressionType" />. /// </summary> private bool IsFormulaType(ITypeSymbol expressionType) { return expressionType.Equals(_formulaType); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { INamedTypeSymbol cancellationTokenType = compilationContext.Compilation.GetTypeByMetadataName("System.Threading.CancellationToken"); if (cancellationTokenType != null) { compilationContext.RegisterSymbolAction(symbolContext => { var methodSymbol = (IMethodSymbol)symbolContext.Symbol; if (methodSymbol.IsOverride || methodSymbol.IsImplementationOfAnyInterfaceMember()) { return; } int last = methodSymbol.Parameters.Length - 1; if (last >= 0 && methodSymbol.Parameters[last].IsParams) { last--; } // Skip optional parameters, UNLESS one of them is a CancellationToken // AND it's not the last one. if (last >= 0 && methodSymbol.Parameters[last].IsOptional && !methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { last--; while (last >= 0 && methodSymbol.Parameters[last].IsOptional) { if (methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { symbolContext.ReportDiagnostic(Diagnostic.Create( Rule, methodSymbol.Locations.First(), methodSymbol.ToDisplayString())); } last--; } } while (last >= 0 && methodSymbol.Parameters[last].RefKind != RefKind.None) { last--; } for (int i = last; i >= 0; i--) { ITypeSymbol parameterType = methodSymbol.Parameters[i].Type; if (parameterType.Equals(cancellationTokenType) && i != last) { symbolContext.ReportDiagnostic(Diagnostic.Create( Rule, methodSymbol.Locations.First(), methodSymbol.ToDisplayString())); break; } } }, SymbolKind.Method); } }); }
public static bool IsSubtypeOf(this ITypeSymbol symbol, ITypeSymbol type) { return(symbol.Equals(type) || symbol.Implements(type) || symbol.InheritsFrom(type)); }
static bool ContainsType (ITypeSymbol testType, ITypeSymbol searchType) { if (testType == null) return false; Console.WriteLine (testType +" == " + searchType + " ? " + (testType == searchType) + "/" + testType.Equals (searchType)); if (testType == searchType) return true; var namedTypeSymbol = testType as INamedTypeSymbol; if (namedTypeSymbol != null) { foreach (var arg in namedTypeSymbol.TypeArguments) if (ContainsType (arg, searchType)) return true; } return false; }
public static bool HasAccessibleIndexer( ITypeSymbol typeSymbol, SemanticModel semanticModel, int position) { if (typeSymbol == null) { return(false); } SymbolKind symbolKind = typeSymbol.Kind; if (symbolKind == SymbolKind.ErrorType) { return(false); } if (symbolKind == SymbolKind.ArrayType) { return(true); } bool?hasIndexer = HasIndexer(typeSymbol.SpecialType); if (hasIndexer != null) { return(hasIndexer.Value); } ITypeSymbol originalDefinition = typeSymbol.OriginalDefinition; if (!typeSymbol.Equals(originalDefinition)) { hasIndexer = HasIndexer(originalDefinition.SpecialType); if (hasIndexer != null) { return(hasIndexer.Value); } } if (originalDefinition.ImplementsAny( SpecialType.System_Collections_Generic_IList_T, SpecialType.System_Collections_Generic_IReadOnlyList_T, allInterfaces: true)) { if (originalDefinition.TypeKind == TypeKind.Interface) { return(true); } foreach (ISymbol symbol in typeSymbol.GetMembers("this[]")) { if (semanticModel.IsAccessible(position, symbol)) { return(true); } } } return(false); bool?HasIndexer(SpecialType specialType) { switch (specialType) { case SpecialType.System_String: case SpecialType.System_Array: case SpecialType.System_Collections_Generic_IList_T: case SpecialType.System_Collections_Generic_IReadOnlyList_T: return(true); case SpecialType.None: return(null); } return(false); } }
protected virtual void CreateVisitStatements(MethodGenerationContext context) { string parameterName = context.ParameterName; ITypeSymbol propertyType = context.PropertyType; string propertyName = context.PropertyName; if (propertyType.OriginalDefinition.Equals(SyntaxListSymbol)) { if (UseCustomVisitMethod) { CreateVisitListStatements(context, isSeparatedList: false); } else { context.AddStatement(VisitStatement("VisitList", parameterName, propertyName)); } } else if (propertyType.OriginalDefinition.Equals(SeparatedSyntaxListSymbol)) { if (UseCustomVisitMethod) { CreateVisitListStatements(context, isSeparatedList: true); } else { context.AddStatement(VisitStatement("VisitSeparatedList", parameterName, propertyName)); } } else if (propertyType.Equals(SyntaxTokenListSymbol)) { if (Depth >= SyntaxWalkerDepth.Token) { context.AddStatement(VisitStatement("VisitTokenList", parameterName, propertyName)); } } else if (propertyType.Equals(SyntaxTokenSymbol)) { if (Depth >= SyntaxWalkerDepth.Token) { context.AddStatement(VisitStatement("VisitToken", parameterName, propertyName)); } } else if (propertyType.EqualsOrInheritsFrom(SyntaxNodeSymbol)) { switch (propertyType.Name) { case "AccessorListSyntax": case "ArgumentListSyntax": case "ArrayTypeSyntax": case "ArrowExpressionClauseSyntax": case "AttributeArgumentListSyntax": case "AttributeTargetSpecifierSyntax": case "BaseListSyntax": case "BlockSyntax": case "BracketedArgumentListSyntax": case "BracketedParameterListSyntax": case "CatchDeclarationSyntax": case "CatchFilterClauseSyntax": case "ConstructorInitializerSyntax": case "CrefBracketedParameterListSyntax": case "CrefParameterListSyntax": case "CrefSyntax": case "ElseClauseSyntax": case "EqualsValueClauseSyntax": case "ExplicitInterfaceSpecifierSyntax": case "ExpressionSyntax": case "FinallyClauseSyntax": case "FromClauseSyntax": case "IdentifierNameSyntax": case "InitializerExpressionSyntax": case "InterpolationAlignmentClauseSyntax": case "InterpolationFormatClauseSyntax": case "JoinIntoClauseSyntax": case "MemberCrefSyntax": case "NameColonSyntax": case "NameEqualsSyntax": case "NameSyntax": case "ParameterListSyntax": case "ParameterSyntax": case "PatternSyntax": case "QueryBodySyntax": case "QueryContinuationSyntax": case "SelectOrGroupClauseSyntax": case "SimpleNameSyntax": case "StatementSyntax": case "TypeArgumentListSyntax": case "TypeParameterListSyntax": case "TypeSyntax": case "VariableDeclarationSyntax": case "VariableDesignationSyntax": case "WhenClauseSyntax": case "XmlElementEndTagSyntax": case "XmlElementStartTagSyntax": case "XmlNameSyntax": case "XmlPrefixSyntax": { if (UseCustomVisitMethod) { CreateTypeVisitStatements(context); } else { context.AddStatement(VisitStatement("Visit", parameterName, propertyName)); } break; } case "CSharpSyntaxNode": { if (!UseCustomVisitMethod) { context.AddStatement(VisitStatement("Visit", parameterName, propertyName)); break; } if (EliminateDefaultVisit && propertyName == "Body" && context.ParameterType.InheritsFrom(Microsoft_CodeAnalysis_CSharp_Syntax_AnonymousFunctionExpressionSyntax)) { CreateVisitAnonymousFunctionStatements(context); } else { CreateTypeVisitStatements(context); } break; } default: { throw new InvalidOperationException($"Unrecognized property type '{propertyType.ToDisplayString()}'."); } } } else if (!propertyType.SpecialType.Is(SpecialType.System_Int32, SpecialType.System_Boolean)) { throw new InvalidOperationException(); } }
public static void AnalyzeAsExpression(SyntaxNodeAnalysisContext context) { var asExpression = (BinaryExpressionSyntax)context.Node; AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(asExpression); if (!asExpressionInfo.Success) { return; } SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(asExpression); if (!localInfo.Success) { return; } if (localInfo.Statement.SpanOrTrailingTriviaContainsDirectives()) { return; } if (!(localInfo.Statement.NextStatement() is IfStatementSyntax ifStatement)) { return; } if (!ifStatement.IsSimpleIf()) { return; } if (ifStatement.SpanOrLeadingTriviaContainsDirectives()) { return; } StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault(); if (statement == null) { return; } if (!CSharpFacts.IsJumpStatement(statement.Kind())) { return; } NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull); if (!nullCheck.Success) { return; } if (!string.Equals(localInfo.IdentifierText, (nullCheck.Expression as IdentifierNameSyntax)?.Identifier.ValueText, StringComparison.Ordinal)) { return; } if (!localInfo.Type.IsVar) { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken); ITypeSymbol typeSymbol2 = semanticModel.GetTypeSymbol(asExpressionInfo.Type, cancellationToken); if (!typeSymbol.Equals(typeSymbol2)) { return; } } context.ReportDiagnostic(DiagnosticDescriptors.UsePatternMatchingInsteadOfAsAndNullCheck, localInfo.Statement); }
/// <summary> /// Classifies the type of the <paramref name="expressionType" />. /// </summary> private ExpressionType DetermineType(ITypeSymbol expressionType) { if (expressionType.Equals(_ctlFormulaType)) return ExpressionType.Ctl; if (expressionType.Equals(_ltlFormulaType)) return ExpressionType.Ltl; return ExpressionType.Other; }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationContext.Compilation); INamedTypeSymbol?cancellationTokenType = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingCancellationToken); INamedTypeSymbol?iprogressType = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIProgress1); if (cancellationTokenType == null) { return; } compilationContext.RegisterSymbolAction(symbolContext => { var methodSymbol = (IMethodSymbol)symbolContext.Symbol; if (methodSymbol.IsOverride || methodSymbol.IsImplementationOfAnyInterfaceMember()) { return; } int last = methodSymbol.Parameters.Length - 1; if (last >= 0 && methodSymbol.Parameters[last].IsParams) { last--; } // Skip optional parameters, UNLESS one of them is a CancellationToken // AND it's not the last one. if (last >= 0 && methodSymbol.Parameters[last].IsOptional && !methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { last--; while (last >= 0 && methodSymbol.Parameters[last].IsOptional) { if (methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { symbolContext.ReportDiagnostic(Diagnostic.Create( Rule, methodSymbol.Locations.First(), methodSymbol.ToDisplayString())); } last--; } } // Ignore multiple cancellation token parameters at the end of the parameter list. while (last >= 0 && methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { last--; } // Ignore parameters passed by reference when they appear at the end of the parameter list. while (last >= 0 && methodSymbol.Parameters[last].RefKind != RefKind.None) { last--; } // Ignore IProgress<T> when last if (last >= 0 && iprogressType != null && methodSymbol.Parameters[last].Type.OriginalDefinition.Equals(iprogressType)) { last--; } for (int i = last - 1; i >= 0; i--) { ITypeSymbol parameterType = methodSymbol.Parameters[i].Type; if (!parameterType.Equals(cancellationTokenType)) { continue; } // Bail if the CancellationToken is the first parameter of an extension method. if (i == 0 && methodSymbol.IsExtensionMethod) { continue; } symbolContext.ReportDiagnostic(Diagnostic.Create( Rule, methodSymbol.Locations.First(), methodSymbol.ToDisplayString())); break; } }, SymbolKind.Method); }); }
public static async Task ComputeRefactoringsAsync(RefactoringContext context, ExpressionSyntax expression) { if (expression != null) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ISymbol memberSymbol = GetContainingMethodOrPropertySymbol(expression, semanticModel, context.CancellationToken); if (memberSymbol != null) { SyntaxNode node = await memberSymbol .DeclaringSyntaxReferences[0] .GetSyntaxAsync(context.CancellationToken) .ConfigureAwait(false); var declaration = node as MemberDeclarationSyntax; if (declaration != null) { TypeSyntax memberType = GetMemberType(declaration); if (memberType != null) { ITypeSymbol memberTypeSymbol = semanticModel.GetTypeSymbol(memberType, context.CancellationToken); if (memberTypeSymbol != null) { ITypeSymbol expressionSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken); if (expressionSymbol?.IsErrorType() == false) { if (context.IsRefactoringEnabled(RefactoringIdentifiers.ChangeMemberTypeAccordingToReturnExpression)) { ITypeSymbol newType = GetMemberNewType(memberSymbol, memberTypeSymbol, expression, expressionSymbol, semanticModel, context.CancellationToken); if (newType?.IsErrorType() == false && !memberTypeSymbol.Equals(newType) && !memberSymbol.IsOverride && !memberSymbol.ImplementsInterfaceMember()) { if (newType.IsNamedType() && memberTypeSymbol.IsNamedType()) { var newNamedType = (INamedTypeSymbol)newType; INamedTypeSymbol orderedEnumerableSymbol = semanticModel.GetTypeByMetadataName(MetadataNames.System_Linq_IOrderedEnumerable_T); if (newNamedType.ConstructedFrom == orderedEnumerableSymbol) { INamedTypeSymbol enumerableSymbol = semanticModel.GetTypeByMetadataName(MetadataNames.System_Collections_Generic_IEnumerable_T); if (enumerableSymbol != null && ((INamedTypeSymbol)memberTypeSymbol).ConstructedFrom != enumerableSymbol) { RegisterChangeType(context, declaration, memberType, enumerableSymbol.Construct(newNamedType.TypeArguments.ToArray()), semanticModel); } } } RegisterChangeType(context, declaration, memberType, newType, semanticModel); } } if (context.IsAnyRefactoringEnabled(RefactoringIdentifiers.AddCastExpression, RefactoringIdentifiers.CallToMethod) && !memberTypeSymbol.IsErrorType()) { ITypeSymbol castTypeSymbol = GetCastTypeSymbol(memberSymbol, memberTypeSymbol, expressionSymbol, semanticModel); if (castTypeSymbol != null) { ModifyExpressionRefactoring.ComputeRefactoring( context, expression, castTypeSymbol, semanticModel); } } } } } } } } }
private bool IsConversionToSimpleTypeNeeded(ITypeSymbol targetType, ITypeSymbol sourceType) { return(targetType.Equals(sourceType) == false && (ObjectHelper.IsSimpleType(targetType) || SymbolHelper.IsNullable(targetType, out _))); }
public override void Initialize(AnalysisContext context) { context.EnableConcurrentExecution(); context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); context.RegisterCompilationStartAction(compilationContext => { var wellKnownTypeProvider = WellKnownTypeProvider.GetOrCreate(compilationContext.Compilation); INamedTypeSymbol?cancellationTokenType = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingCancellationToken); INamedTypeSymbol?iprogressType = wellKnownTypeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemIProgress1); var builder = ImmutableHashSet.CreateBuilder <INamedTypeSymbol>(); builder.AddIfNotNull(compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeCompilerServicesCallerFilePathAttribute)); builder.AddIfNotNull(compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeCompilerServicesCallerLineNumberAttribute)); builder.AddIfNotNull(compilationContext.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeCompilerServicesCallerMemberNameAttribute)); var callerInformationAttributes = builder.ToImmutable(); if (cancellationTokenType == null) { return; } compilationContext.RegisterSymbolAction(symbolContext => { var methodSymbol = (IMethodSymbol)symbolContext.Symbol; if (methodSymbol.IsOverride || methodSymbol.IsImplementationOfAnyInterfaceMember()) { return; } int last = methodSymbol.Parameters.Length - 1; if (last >= 0 && methodSymbol.Parameters[last].IsParams) { last--; } // Ignore parameters that have any of these attributes. // C# reserved attributes: https://docs.microsoft.com/dotnet/csharp/language-reference/attributes/caller-information while (last >= 0 && HasCallerInformationAttribute(methodSymbol.Parameters[last], callerInformationAttributes)) { last--; } // Skip optional parameters, UNLESS one of them is a CancellationToken // AND it's not the last one. if (last >= 0 && methodSymbol.Parameters[last].IsOptional && !methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { last--; while (last >= 0 && methodSymbol.Parameters[last].IsOptional) { if (methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { symbolContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(Rule, methodSymbol.ToDisplayString())); } last--; } } // Ignore multiple cancellation token parameters at the end of the parameter list. while (last >= 0 && methodSymbol.Parameters[last].Type.Equals(cancellationTokenType)) { last--; } // Ignore parameters passed by reference when they appear at the end of the parameter list. while (last >= 0 && methodSymbol.Parameters[last].RefKind != RefKind.None) { last--; } // Ignore IProgress<T> when last if (last >= 0 && iprogressType != null && methodSymbol.Parameters[last].Type.OriginalDefinition.Equals(iprogressType)) { last--; } for (int i = last - 1; i >= 0; i--) { ITypeSymbol parameterType = methodSymbol.Parameters[i].Type; if (!parameterType.Equals(cancellationTokenType)) { continue; } // Bail if the CancellationToken is the first parameter of an extension method. if (i == 0 && methodSymbol.IsExtensionMethod) { continue; } symbolContext.ReportDiagnostic(methodSymbol.CreateDiagnostic(Rule, methodSymbol.ToDisplayString())); break; } }, SymbolKind.Method); }); }
public static void Analyze(SyntaxNodeAnalysisContext context, SimpleMemberInvocationExpressionInfo invocationInfo) { SimpleMemberInvocationExpressionInfo invocationInfo2 = SyntaxInfo.SimpleMemberInvocationExpressionInfo(invocationInfo.Expression); if (!invocationInfo2.Success) { return; } ArgumentSyntax argument = invocationInfo2.Arguments.SingleOrDefault(shouldThrow: false); if (argument == null) { return; } if (!string.Equals(invocationInfo2.NameText, "Where", StringComparison.Ordinal)) { return; } SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IMethodSymbol methodSymbol = semanticModel.GetReducedExtensionMethodInfo(invocationInfo.InvocationExpression, cancellationToken).Symbol; if (methodSymbol == null) { return; } if (!SymbolUtility.IsLinqCast(methodSymbol, semanticModel)) { return; } IMethodSymbol methodSymbol2 = semanticModel.GetReducedExtensionMethodInfo(invocationInfo2.InvocationExpression, cancellationToken).Symbol; if (methodSymbol2 == null) { return; } if (!SymbolUtility.IsLinqWhere(methodSymbol2, semanticModel)) { return; } IsExpressionInfo isExpressionInfo = SyntaxInfo.IsExpressionInfo(GetLambdaExpression(argument.Expression)); if (!isExpressionInfo.Success) { return; } TypeSyntax type2 = (invocationInfo.Name as GenericNameSyntax)?.TypeArgumentList?.Arguments.SingleOrDefault(shouldThrow: false); if (type2 == null) { return; } ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(isExpressionInfo.Type, cancellationToken); if (typeSymbol == null) { return; } ITypeSymbol typeSymbol2 = semanticModel.GetTypeSymbol(type2, cancellationToken); if (!typeSymbol.Equals(typeSymbol2)) { return; } TextSpan span = TextSpan.FromBounds(invocationInfo2.Name.SpanStart, invocationInfo.InvocationExpression.Span.End); if (invocationInfo.InvocationExpression.ContainsDirectives(span)) { return; } context.ReportDiagnostic( DiagnosticDescriptors.SimplifyLinqMethodChain, Location.Create(invocationInfo.InvocationExpression.SyntaxTree, span)); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression) && !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindNode(root, context.Span, out ExpressionSyntax expression)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertTypeExplicitConversionExists: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeInfo typeInfo = semanticModel.GetTypeInfo(expression, context.CancellationToken); ITypeSymbol type = typeInfo.Type; ITypeSymbol convertedType = typeInfo.ConvertedType; if (type?.IsNamedType() == true) { var namedType = (INamedTypeSymbol)type; if (namedType.ConstructedFrom.SpecialType == SpecialType.System_Nullable_T) { if (convertedType?.IsBoolean() == true || AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression)) { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral)) { CodeAction codeAction = CodeAction.Create( AddComparisonWithBooleanLiteralRefactoring.GetTitle(expression), cancellationToken => AddComparisonWithBooleanLiteralRefactoring.RefactorAsync(context.Document, expression, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.AddComparisonWithBooleanLiteral)); context.RegisterCodeFix(codeAction, diagnostic); } } else if (namedType.TypeArguments[0].Equals(convertedType)) { if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseCoalesceExpression)) { CodeAction codeAction = CodeAction.Create( "Use coalesce expression", cancellationToken => { ExpressionSyntax defaultValue = convertedType.ToDefaultValueSyntax(semanticModel, expression.SpanStart); ExpressionSyntax newNode = CoalesceExpression(expression.WithoutTrivia(), defaultValue) .WithTriviaFrom(expression) .Parenthesize() .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic, CodeFixIdentifiers.UseCoalesceExpression)); context.RegisterCodeFix(codeAction, diagnostic); } } } } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) && type?.IsErrorType() == false && !type.Equals(convertedType) && convertedType.IsArrayType()) { var arrayType = (IArrayTypeSymbol)convertedType; if (semanticModel.IsImplicitConversion(expression, arrayType.ElementType)) { CodeAction codeAction = CodeAction.Create( "Create singleton array", cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic, CodeFixIdentifiers.CreateSingletonArray)); context.RegisterCodeFix(codeAction, diagnostic); } } break; } case CompilerDiagnosticIdentifiers.ConstantValueCannotBeConverted: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression)) { break; } CodeAction codeAction = CodeAction.Create( "Use 'unchecked'", cancellationToken => { CheckedExpressionSyntax newNode = CSharpFactory.UncheckedExpression(expression.WithoutTrivia()); newNode = newNode.WithTriviaFrom(expression); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ExpressionBeingAssignedMustBeConstant: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier)) { break; } LocalDeclarationStatementSyntax localDeclarationStatement = GetLocalDeclarationStatement(expression); if (localDeclarationStatement == null) { break; } SyntaxTokenList modifiers = localDeclarationStatement.Modifiers; if (!modifiers.Contains(SyntaxKind.ConstKeyword)) { break; } CodeAction codeAction = CodeAction.Create( "Remove 'const' modifier", cancellationToken => { LocalDeclarationStatementSyntax newNode = localDeclarationStatement.RemoveModifier(SyntaxKind.ConstKeyword); return(context.Document.ReplaceNodeAsync(localDeclarationStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType; if (typeSymbol?.SupportsExplicitDeclaration() == true) { CodeAction codeAction = CodeAction.Create( "Replace 'null' with default value", cancellationToken => { ExpressionSyntax newNode = typeSymbol.ToDefaultValueSyntax(semanticModel, expression.SpanStart); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } case CompilerDiagnosticIdentifiers.ResultOfExpressionIsAlwaysConstantSinceValueIsNeverEqualToNull: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConditionThatIsAlwaysEqualToTrueOrFalse)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); if (!NullCheckExpression.TryCreate(expression, semanticModel, out NullCheckExpression nullCheck, context.CancellationToken)) { break; } if (nullCheck.Kind != NullCheckKind.EqualsToNull && nullCheck.Kind != NullCheckKind.NotEqualsToNull) { break; } CodeAction codeAction = CodeAction.Create( "Remove condition", cancellationToken => { SyntaxNode newRoot = RemoveHelper.RemoveCondition(root, expression, nullCheck.Kind == NullCheckKind.NotEqualsToNull); return(Task.FromResult(context.Document.WithSyntaxRoot(newRoot))); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } }
static bool IsArrayTypeSomeObviousTypeCase(SyntaxNodeAnalysisContext nodeContext, ExpressionSyntax initializerExpression, ITypeSymbol variableType, LocalDeclarationStatementSyntax localVariable) { var arrayCreationExpressionSyntax = initializerExpression as ArrayCreationExpressionSyntax; if (arrayCreationExpressionSyntax != null) { if (arrayCreationExpressionSyntax.Type.IsMissing) return false; var arrayType = nodeContext.SemanticModel.GetTypeInfo(arrayCreationExpressionSyntax).ConvertedType; return arrayType != null && arrayCreationExpressionSyntax.Initializer != null && variableType.Equals(arrayType); } return false; }
protected override bool IsSyntaxKind(ITypeSymbol type) { return((_csharpSyntaxKind != null && type.Equals(_csharpSyntaxKind)) || (_basicSyntaxKind != null && type.Equals(_basicSyntaxKind))); }
private bool IsCorrectTypeForYieldReturn(ITypeSymbol returnExpressionType, ITypeSymbol methodReturnType, SemanticModel model) { var ienumerableSymbol = model.Compilation.GetTypeByMetadataName("System.Collections.IEnumerable"); var ienumeratorSymbol = model.Compilation.GetTypeByMetadataName("System.Collections.IEnumerator"); if (ienumerableSymbol == null || ienumeratorSymbol == null) { return false; } if (!(methodReturnType.Equals(ienumerableSymbol) || methodReturnType.Equals(ienumeratorSymbol))) { return false; } return true; }
public static bool Analyze(SyntaxNodeAnalysisContext context, InvocationExpressionSyntax invocation) { var memberAccess = (MemberAccessExpressionSyntax)invocation.Expression; ExpressionSyntax expression = memberAccess?.Expression; if (expression?.IsKind(SyntaxKind.InvocationExpression) == true) { var invocation2 = (InvocationExpressionSyntax)expression; ArgumentListSyntax argumentList = invocation2.ArgumentList; if (argumentList?.IsMissing == false) { SeparatedSyntaxList <ArgumentSyntax> arguments = argumentList.Arguments; if (arguments.Count == 1 && invocation2.Expression?.IsKind(SyntaxKind.SimpleMemberAccessExpression) == true) { var memberAccess2 = (MemberAccessExpressionSyntax)invocation2.Expression; if (string.Equals(memberAccess2.Name?.Identifier.ValueText, "Where", StringComparison.Ordinal)) { SemanticModel semanticModel = context.SemanticModel; CancellationToken cancellationToken = context.CancellationToken; IMethodSymbol invocationSymbol = semanticModel.GetMethodSymbol(invocation, cancellationToken); if (invocationSymbol != null && IsEnumerableCastMethod(invocationSymbol, semanticModel)) { IMethodSymbol invocation2Symbol = semanticModel.GetMethodSymbol(invocation2, cancellationToken); if (invocation2Symbol != null && (Symbol.IsEnumerableMethodWithPredicate(invocation2Symbol, "Where", semanticModel))) { BinaryExpressionSyntax isExpression = GetIsExpression(arguments.First().Expression); if (isExpression != null) { var type = isExpression.Right as TypeSyntax; if (type != null) { TypeSyntax type2 = GetTypeArgument(memberAccess.Name); if (type2 != null) { ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(type); if (typeSymbol != null) { ITypeSymbol typeSymbol2 = semanticModel.GetTypeSymbol(type2); if (typeSymbol.Equals(typeSymbol2)) { TextSpan span = TextSpan.FromBounds(memberAccess2.Name.Span.Start, invocation.Span.End); if (!invocation.ContainsDirectives(span)) { context.ReportDiagnostic( DiagnosticDescriptors.SimplifyLinqMethodChain, Location.Create(invocation.SyntaxTree, span)); } return(true); } } } } } } } } } } } return(false); }
public bool ShouldPreferExplicitType(VBSyntax.ExpressionSyntax exp, ITypeSymbol expConvertedType, out bool isNothingLiteral) { var op = SemanticModel.GetExpressionOperation(exp); exp = op.Syntax as VBSyntax.ExpressionSyntax; var vbInitConstantValue = SemanticModel.GetConstantValue(exp); isNothingLiteral = vbInitConstantValue.HasValue && vbInitConstantValue.Value == null || exp is VBSyntax.LiteralExpressionSyntax les && les.IsKind(SyntaxKind.NothingLiteralExpression); bool shouldPreferExplicitType = expConvertedType != null && (expConvertedType.HasCsKeyword() || !expConvertedType.Equals(op.Type, SymbolEqualityComparer.IncludeNullability)); return(shouldPreferExplicitType); }
public static string GetCountOrLengthPropertyName( ITypeSymbol typeSymbol, SemanticModel semanticModel, int position) { SymbolKind kind = typeSymbol.Kind; if (kind == SymbolKind.ErrorType) { return(null); } if (kind == SymbolKind.ArrayType) { return("Length"); } string propertyName = GetCountOrLengthPropertyName(typeSymbol.SpecialType); if (propertyName != null) { return((propertyName.Length > 0) ? propertyName : null); } ITypeSymbol originalDefinition = typeSymbol.OriginalDefinition; if (!typeSymbol.Equals(originalDefinition)) { propertyName = GetCountOrLengthPropertyName(originalDefinition.SpecialType); if (propertyName != null) { return((propertyName.Length > 0) ? propertyName : null); } } if (originalDefinition.ImplementsAny( SpecialType.System_Collections_Generic_ICollection_T, SpecialType.System_Collections_Generic_IReadOnlyCollection_T, allInterfaces: true)) { if (originalDefinition.TypeKind == TypeKind.Interface) { return("Count"); } foreach (ISymbol symbol in typeSymbol.GetMembers()) { if (symbol.Kind == SymbolKind.Property && StringUtility.Equals(symbol.Name, "Count", "Length") && semanticModel.IsAccessible(position, symbol)) { return(symbol.Name); } } } return(null); string GetCountOrLengthPropertyName(SpecialType specialType) { switch (specialType) { case SpecialType.System_String: case SpecialType.System_Array: return("Length"); case SpecialType.System_Collections_Generic_IList_T: case SpecialType.System_Collections_Generic_ICollection_T: case SpecialType.System_Collections_Generic_IReadOnlyList_T: case SpecialType.System_Collections_Generic_IReadOnlyCollection_T: return("Count"); case SpecialType.None: return(null); } return(""); } }
/// <remarks> /// If there are type arguments on either side of assignment, we match type names instead of type equality /// to account for inferred generic type arguments. /// e.g: Tuple.Create(0, true) returns Tuple<X,y> which isn't the same as type Tuple. /// otherwise, we match for type equivalence /// </remarks> private static bool IsContainerTypeEqualToReturnType(IMethodSymbol methodSymbol, ITypeSymbol typeInDeclaration, ITypeSymbol containingType) { var returnType = methodSymbol.ReturnType; if (typeInDeclaration?.GetTypeArguments().Length > 0 || containingType.GetTypeArguments().Length > 0) { return containingType.Name.Equals(returnType.Name); } else { return containingType.Equals(returnType); } }
public static bool IsDefaultValue( this SemanticModel semanticModel, ITypeSymbol typeSymbol, ExpressionSyntax expression, CancellationToken cancellationToken = default(CancellationToken)) { if (semanticModel == null) { throw new ArgumentNullException(nameof(semanticModel)); } if (typeSymbol == null) { throw new ArgumentNullException(nameof(typeSymbol)); } if (expression == null) { throw new ArgumentNullException(nameof(expression)); } if (typeSymbol.IsErrorType()) { return(false); } SyntaxKind kind = expression.Kind(); switch (typeSymbol.SpecialType) { case SpecialType.System_Void: return(false); case SpecialType.System_Boolean: return(semanticModel.IsConstantValue(expression, false, cancellationToken)); case SpecialType.System_Char: return(semanticModel.IsConstantValue(expression, '\0', cancellationToken)); case SpecialType.System_SByte: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Byte: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Int16: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_UInt16: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Int32: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_UInt32: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Int64: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_UInt64: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Decimal: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Single: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Double: return(semanticModel.IsConstantValue(expression, cancellationToken)); } if (typeSymbol.IsEnum()) { INamedTypeSymbol underlyingType = ((INamedTypeSymbol)typeSymbol).EnumUnderlyingType; switch (underlyingType.SpecialType) { case SpecialType.System_SByte: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Byte: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Int16: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_UInt16: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Int32: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_UInt32: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_Int64: return(semanticModel.IsConstantValue(expression, cancellationToken)); case SpecialType.System_UInt64: return(semanticModel.IsConstantValue(expression, cancellationToken)); } Debug.Assert(false, underlyingType.SpecialType.ToString()); return(false); } if (typeSymbol.IsReferenceType) { if (kind == SyntaxKind.NullLiteralExpression) { return(true); } else { Optional <object> optional = semanticModel.GetConstantValue(expression, cancellationToken); if (optional.HasValue) { return(optional.Value == null); } } } if (typeSymbol.IsConstructedFrom(SpecialType.System_Nullable_T) && kind == SyntaxKind.NullLiteralExpression) { return(true); } if (kind == SyntaxKind.DefaultExpression) { var defaultExpression = (DefaultExpressionSyntax)expression; TypeSyntax type = defaultExpression.Type; return(type != null && typeSymbol.Equals(semanticModel.GetTypeSymbol(type, cancellationToken))); } return(false); }
static bool IsObjectCreationSomeObviousTypeCase(SyntaxNodeAnalysisContext nodeContext, ExpressionSyntax initializerExpression, ITypeSymbol variableType) { var objectCreationExpressionSyntax = initializerExpression as ObjectCreationExpressionSyntax; if (objectCreationExpressionSyntax != null) { var objectType = nodeContext.SemanticModel.GetTypeInfo(objectCreationExpressionSyntax, nodeContext.CancellationToken).ConvertedType; return objectType != null && variableType.Equals(objectType); } return false; }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsAnyCodeFixEnabled( CodeFixIdentifiers.AddComparisonWithBooleanLiteral, CodeFixIdentifiers.CreateSingletonArray, CodeFixIdentifiers.UseUncheckedExpression, CodeFixIdentifiers.RemoveConstModifier, CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); var expression = root.FindNode(context.Span, getInnermostNodeForTie: true) as ExpressionSyntax; Debug.Assert(expression != null, $"{nameof(expression)} is null"); if (expression == null) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.CannotImplicitlyConvertTypeExplicitConversionExists: { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); TypeInfo typeInfo = semanticModel.GetTypeInfo(expression, context.CancellationToken); ITypeSymbol type = typeInfo.Type; ITypeSymbol convertedType = typeInfo.ConvertedType; if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddComparisonWithBooleanLiteral) && type?.IsNullableOf(SpecialType.System_Boolean) == true) { if (convertedType?.IsBoolean() == true || AddComparisonWithBooleanLiteralRefactoring.IsCondition(expression)) { CodeAction codeAction = CodeAction.Create( AddComparisonWithBooleanLiteralRefactoring.GetTitle(expression), cancellationToken => AddComparisonWithBooleanLiteralRefactoring.RefactorAsync(context.Document, expression, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.CreateSingletonArray) && type?.IsErrorType() == false && !type.Equals(convertedType) && convertedType.IsArrayType()) { var arrayType = (IArrayTypeSymbol)convertedType; if (semanticModel.IsImplicitConversion(expression, arrayType.ElementType)) { CodeAction codeAction = CodeAction.Create( "Create singleton array", cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } } break; } case CompilerDiagnosticIdentifiers.ConstantValueCannotBeConverted: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.UseUncheckedExpression)) { break; } CodeAction codeAction = CodeAction.Create( "Use 'unchecked'", cancellationToken => { CheckedExpressionSyntax newNode = CSharpFactory.UncheckedExpression(expression.WithoutTrivia()); newNode = newNode.WithTriviaFrom(expression); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ExpressionBeingAssignedMustBeConstant: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveConstModifier)) { break; } LocalDeclarationStatementSyntax localDeclarationStatement = GetLocalDeclarationStatement(expression); if (localDeclarationStatement == null) { break; } SyntaxTokenList modifiers = localDeclarationStatement.Modifiers; if (!modifiers.Contains(SyntaxKind.ConstKeyword)) { break; } CodeAction codeAction = CodeAction.Create( "Remove 'const' modifier", cancellationToken => { LocalDeclarationStatementSyntax newNode = localDeclarationStatement.RemoveModifier(SyntaxKind.ConstKeyword); return(context.Document.ReplaceNodeAsync(localDeclarationStatement, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CannotConvertNullToTypeBecauseItIsNonNullableValueType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ReplaceNullLiteralExpressionWithDefaultValue)) { break; } SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeInfo(expression, context.CancellationToken).ConvertedType; if (typeSymbol?.SupportsExplicitDeclaration() == true) { CodeAction codeAction = CodeAction.Create( "Replace 'null' with default value", cancellationToken => { ExpressionSyntax newNode = typeSymbol.ToDefaultValueSyntax(semanticModel, expression.SpanStart); return(context.Document.ReplaceNodeAsync(expression, newNode, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); } break; } } } }
/// <summary> /// Adds to <paramref name="targetType"/> if it does not contain an anonymous /// type and binds to the same type at the given <paramref name="position"/>. /// </summary> public static ExpressionSyntax CastIfPossible( this ExpressionSyntax expression, ITypeSymbol targetType, int position, SemanticModel semanticModel, out bool wasCastAdded) { wasCastAdded = false; if (targetType.ContainsAnonymousType()) { return expression; } if (targetType.Kind == SymbolKind.DynamicType) { targetType = semanticModel.Compilation.GetSpecialType(SpecialType.System_Object); } var typeSyntax = targetType.GenerateTypeSyntax(); var type = semanticModel.GetSpeculativeTypeInfo( position, typeSyntax, SpeculativeBindingOption.BindAsTypeOrNamespace).Type; if (!targetType.Equals(type)) { return expression; } var castExpression = expression.Cast(targetType); // Ensure that inserting the cast doesn't change the semantics. var specAnalyzer = new SpeculationAnalyzer(expression, castExpression, semanticModel, CancellationToken.None); var speculativeSemanticModel = specAnalyzer.SpeculativeSemanticModel; if (speculativeSemanticModel == null) { return expression; } var speculatedCastExpression = (CastExpressionSyntax)specAnalyzer.ReplacedExpression; if (!speculatedCastExpression.IsUnnecessaryCast(speculativeSemanticModel, CancellationToken.None)) { return expression; } wasCastAdded = true; return castExpression; }
public override SyntaxNode VisitArgument(ArgumentSyntax node) { var ti = this.semanticModel.GetTypeInfo(node.Expression); ITypeSymbol type = null; IMethodSymbol method = null; IParameterSymbol parameter = null; if (ti.Type != null && ti.Type.TypeKind == TypeKind.Delegate) { type = ti.Type; } else if (ti.ConvertedType != null && ti.ConvertedType.TypeKind == TypeKind.Delegate) { type = ti.ConvertedType; } if (type != null) { var list = node.Parent as ArgumentListSyntax; var invocation = node.Parent.Parent as InvocationExpressionSyntax; if (list != null && invocation != null) { method = this.semanticModel.GetSymbolInfo(invocation).Symbol as IMethodSymbol; if (method != null) { if (node.NameColon != null) { if (node.NameColon.Name != null) { var nameText = node.NameColon.Name.Identifier.ValueText; if (nameText != null) { foreach (var p in method.Parameters) { if (string.Equals(p.Name, nameText, StringComparison.Ordinal)) { parameter = p; break; } } } } } else { var index = list.Arguments.IndexOf(node); if (index >= 0) { if (index < method.Parameters.Length) { parameter = method.Parameters[index]; } else if (index >= method.Parameters.Length && method.Parameters[method.Parameters.Length - 1].IsParams) { parameter = method.Parameters[method.Parameters.Length - 1]; } } } } } } var isParam = parameter != null && !SyntaxHelper.IsAnonymous(parameter.Type); var parent = isParam && parameter.IsParams ? (InvocationExpressionSyntax)node.Parent.Parent : null; node = (ArgumentSyntax)base.VisitArgument(node); if (isParam) { var pType = parameter.Type; if (parameter.IsParams && SharpSixRewriter.IsExpandedForm(this.semanticModel, parent, method)) { pType = ((IArrayTypeSymbol)parameter.Type).ElementType; } if (node.Expression is CastExpressionSyntax && type.Equals(pType) || parameter.RefKind != RefKind.None) { return(node); } if (pType.TypeKind == TypeKind.Delegate || parameter.IsParams && ((IArrayTypeSymbol)parameter.Type).ElementType.TypeKind == TypeKind.Delegate) { var name = SyntaxFactory.IdentifierName(pType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)).WithoutTrivia(); var expr = node.Expression; if (expr is LambdaExpressionSyntax || expr is AnonymousMethodExpressionSyntax) { expr = SyntaxFactory.ParenthesizedExpression(expr); } var cast = SyntaxFactory.CastExpression(name, expr); node = node.WithExpression(cast); } } return(node); }
private bool IsCorrectTypeForYieldReturn(ITypeSymbol typeArgument, ITypeSymbol returnExpressionType, ITypeSymbol methodReturnType, SemanticModel model) { var ienumerableSymbol = model.Compilation.GetTypeByMetadataName("System.Collections.IEnumerable"); var ienumeratorSymbol = model.Compilation.GetTypeByMetadataName("System.Collections.IEnumerator"); var ienumerableGenericSymbol = model.Compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1"); var ienumeratorGenericSymbol = model.Compilation.GetTypeByMetadataName("System.Collections.Generic.IEnumerator`1"); if (ienumerableGenericSymbol == null || ienumerableSymbol == null || ienumeratorGenericSymbol == null || ienumeratorSymbol == null) { return false; } ienumerableGenericSymbol = ienumerableGenericSymbol.Construct(typeArgument); ienumeratorGenericSymbol = ienumeratorGenericSymbol.Construct(typeArgument); if (!CanConvertTypes(typeArgument, returnExpressionType, model)) { return false; } if (!(methodReturnType.Equals(ienumerableGenericSymbol) || methodReturnType.Equals(ienumerableSymbol) || methodReturnType.Equals(ienumeratorGenericSymbol) || methodReturnType.Equals(ienumeratorSymbol))) { return false; } return true; }
public override SyntaxNode VisitIdentifierName(IdentifierNameSyntax node) { var symbol = semanticModel.GetSymbolInfo(node).Symbol; var parent = node.Parent; while (parent != null && !(parent is TypeDeclarationSyntax)) { parent = parent.Parent; } ITypeSymbol thisType = null; if (parent is TypeDeclarationSyntax) { thisType = this.semanticModel.GetDeclaredSymbol(parent) as ITypeSymbol; } bool needHandle = !node.IsVar && symbol is ITypeSymbol && symbol.ContainingType != null && thisType != null && !thisType.InheritsFromOrEquals(symbol.ContainingType) && !thisType.Equals(symbol); var qns = node.Parent as QualifiedNameSyntax; if (qns != null && needHandle) { SyntaxNode n = node; do { if (!qns.Left.Equals(n)) { needHandle = false; } n = qns; qns = qns.Parent as QualifiedNameSyntax; } while (qns != null && needHandle); } node = (IdentifierNameSyntax)base.VisitIdentifierName(node); if (needHandle && !(node.Parent is MemberAccessExpressionSyntax)) { INamedTypeSymbol namedType = symbol as INamedTypeSymbol; if (namedType != null && namedType.IsGenericType && namedType.TypeArguments.Length > 0 && !namedType.TypeArguments.Any(SyntaxHelper.IsAnonymous)) { var genericName = SyntaxHelper.GenerateGenericName(node.Identifier, namedType.TypeArguments); return(genericName.WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia())); } return(SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(node.GetLeadingTrivia(), symbol.FullyQualifiedName(), node.GetTrailingTrivia()))); } IMethodSymbol methodSymbol = null; if (symbol != null && symbol.IsStatic && symbol.ContainingType != null && thisType != null && !thisType.InheritsFromOrEquals(symbol.ContainingType) && !(node.Parent is MemberAccessExpressionSyntax) && ( (methodSymbol = symbol as IMethodSymbol) != null || symbol is IPropertySymbol || symbol is IFieldSymbol || symbol is IEventSymbol) ) { if (methodSymbol != null && methodSymbol.IsGenericMethod && methodSymbol.TypeArguments.Length > 0 && !methodSymbol.TypeArguments.Any(SyntaxHelper.IsAnonymous)) { var genericName = SyntaxHelper.GenerateGenericName(node.Identifier, methodSymbol.TypeArguments); return(genericName.WithLeadingTrivia(node.GetLeadingTrivia()).WithTrailingTrivia(node.GetTrailingTrivia())); } return(SyntaxFactory.IdentifierName(SyntaxFactory.Identifier(node.GetLeadingTrivia(), symbol.FullyQualifiedName(), node.GetTrailingTrivia()))); } return(node); }
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) { if (!Settings.IsAnyCodeFixEnabled( CodeFixIdentifiers.AddOutModifierToArgument, CodeFixIdentifiers.RemoveRefModifier, CodeFixIdentifiers.CreateSingletonArray)) { return; } SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false); if (!TryFindFirstAncestorOrSelf(root, context.Span, out ArgumentSyntax argument)) { return; } foreach (Diagnostic diagnostic in context.Diagnostics) { switch (diagnostic.Id) { case CompilerDiagnosticIdentifiers.ArgumentMustBePassedWithOutKeyword: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddOutModifierToArgument)) { return; } CodeAction codeAction = CodeAction.Create( "Add 'out' modifier", cancellationToken => { ArgumentSyntax newArgument = argument .WithRefOrOutKeyword(CSharpFactory.OutKeyword()) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(argument, newArgument, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.ArgumentMayNotBePassedWithRefKeyword: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier)) { return; } CodeAction codeAction = CodeAction.Create( "Remove 'ref' modifier", cancellationToken => { ArgumentSyntax newArgument = argument .WithRefOrOutKeyword(default(SyntaxToken)) .PrependToLeadingTrivia(argument.RefOrOutKeyword.GetLeadingAndTrailingTrivia()) .WithFormatterAnnotation(); return(context.Document.ReplaceNodeAsync(argument, newArgument, cancellationToken)); }, GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } case CompilerDiagnosticIdentifiers.CannotConvertArgumentType: { if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddOutModifierToArgument)) { return; } ExpressionSyntax expression = argument.Expression; if (expression?.IsMissing == false) { SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false); ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(expression); if (typeSymbol?.IsErrorType() == false) { foreach (ITypeSymbol typeSymbol2 in DetermineParameterTypeHelper.DetermineParameterTypes(argument, semanticModel, context.CancellationToken)) { if (!typeSymbol.Equals(typeSymbol2) && typeSymbol2.IsArrayType()) { var arrayType = (IArrayTypeSymbol)typeSymbol2; if (semanticModel.IsImplicitConversion(expression, arrayType.ElementType)) { CodeAction codeAction = CodeAction.Create( "Create singleton array", cancellationToken => CreateSingletonArrayRefactoring.RefactorAsync(context.Document, expression, arrayType.ElementType, semanticModel, cancellationToken), GetEquivalenceKey(diagnostic)); context.RegisterCodeFix(codeAction, diagnostic); break; } } } } } break; } } } }
protected static bool IsInvocationSomeObviousTypeCase(SyntaxNodeAnalysisContext nodeContext, ExpressionSyntax initializerExpression, ITypeSymbol variableType) { var invocationExpression = initializerExpression as InvocationExpressionSyntax; if (invocationExpression != null) { var invokedMethod = nodeContext.SemanticModel.GetSymbolInfo(invocationExpression, nodeContext.CancellationToken).Symbol as IMethodSymbol; return invokedMethod != null && variableType.Equals(invokedMethod.ReturnType); } return false; }