private ReferenceRewriter( SemanticModel semanticModel, VariableDeclaratorSyntax variableDeclarator, ExpressionSyntax expressionToInline, CancellationToken cancellationToken) { _semanticModel = semanticModel; _localSymbol = (ILocalSymbol)semanticModel.GetDeclaredSymbol(variableDeclarator, cancellationToken); _variableDeclarator = variableDeclarator; _expressionToInline = expressionToInline; _cancellationToken = cancellationToken; }
private static SyntaxNode CreateRootAddingDisposeToEndOfMethod(SyntaxNode root, ExpressionStatementSyntax statement, ILocalSymbol identitySymbol) { var method = statement.FirstAncestorOrSelf<MethodDeclarationSyntax>(); var newDispose = ImplementsDisposableExplicitly(identitySymbol.Type) ? SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParenthesizedExpression(SyntaxFactory.CastExpression(SyntaxFactory.ParseName("System.IDisposable").WithAdditionalAnnotations(Simplifier.Annotation), SyntaxFactory.IdentifierName(identitySymbol.Name))), SyntaxFactory.IdentifierName("Dispose")))) : SyntaxFactory.ParseStatement($"{identitySymbol.Name}.Dispose();"); newDispose = newDispose.WithAdditionalAnnotations(Formatter.Annotation); var last = method.Body.Statements.Last(); var newRoot = root.InsertNodesAfter(method.Body.Statements.Last(), new[] { newDispose }); return newRoot; }
private static bool IsDisposedOrAssigned(SemanticModel semanticModel, SyntaxNode node, ILocalSymbol identitySymbol) { var method = node.FirstAncestorOrSelf<MethodDeclarationSyntax>(); if (method == null) return false; if (IsReturned(method, semanticModel, identitySymbol)) return true; foreach (var statement in method.Body.DescendantNodes().OfType<StatementSyntax>()) { if (statement.SpanStart > node.SpanStart && (IsCorrectDispose(statement as ExpressionStatementSyntax, semanticModel, identitySymbol) || IsAssignedToField(statement as ExpressionStatementSyntax, semanticModel, identitySymbol))) return true; } return false; }
/// <summary> /// Creates a new LocalDefinition. /// </summary> /// <param name="symbolOpt">Local symbol, used by edit and continue only, null otherwise.</param> /// <param name="nameOpt">Name associated with the slot.</param> /// <param name="type">Type associated with the slot.</param> /// <param name="slot">Slot position in the signature.</param> /// <param name="synthesizedKind">Local kind.</param> /// <param name="id">Local id.</param> /// <param name="pdbAttributes">Value to emit in the attributes field in the PDB.</param> /// <param name="constraints">Specifies whether slot type should have pinned modifier and whether slot should have byref constraint.</param> /// <param name="dynamicTransformFlags">The synthesized dynamic attributes of the local.</param> /// <param name="tupleElementNames">Tuple element names of the local.</param> public LocalDefinition( ILocalSymbol symbolOpt, string nameOpt, Cci.ITypeReference type, int slot, SynthesizedLocalKind synthesizedKind, LocalDebugId id, LocalVariableAttributes pdbAttributes, LocalSlotConstraints constraints, ImmutableArray<TypedConstant> dynamicTransformFlags, ImmutableArray<TypedConstant> tupleElementNames) { _symbolOpt = symbolOpt; _nameOpt = nameOpt; _type = type; _slot = slot; _slotInfo = new LocalSlotDebugInfo(synthesizedKind, id); _pdbAttributes = pdbAttributes; _dynamicTransformFlags = dynamicTransformFlags.NullToEmpty(); _tupleElementNames = tupleElementNames.NullToEmpty(); _constraints = constraints; }
/// <summary> /// Creates a new LocalDefinition. /// </summary> /// <param name="symbolOpt">Local symbol, used by edit and continue only, null otherwise.</param> /// <param name="nameOpt">Name associated with the slot.</param> /// <param name="type">Type associated with the slot.</param> /// <param name="slot">Slot position in the signature.</param> /// <param name="dynamicTransformFlags">Contains the synthesized dynamic attributes of the local</param> /// <param name="synthesizedKind">Local kind.</param> /// <param name="id">Local id.</param> /// <param name="pdbAttributes">Value to emit in the attributes field in the PDB.</param> /// <param name="constraints">Specifies whether slot type should have pinned modifier and whether slot should have byref constraint.</param> /// <param name="isDynamic">Specifies if the type is Dynamic.</param> public LocalDefinition( ILocalSymbol symbolOpt, string nameOpt, Cci.ITypeReference type, int slot, SynthesizedLocalKind synthesizedKind, LocalDebugId id, uint pdbAttributes, LocalSlotConstraints constraints, bool isDynamic, ImmutableArray<TypedConstant> dynamicTransformFlags) { _symbolOpt = symbolOpt; _nameOpt = nameOpt; _type = type; _slot = slot; _slotInfo = new LocalSlotDebugInfo(synthesizedKind, id); _pdbAttributes = pdbAttributes; _dynamicTransformFlags = dynamicTransformFlags; _constraints = constraints; _isDynamic = isDynamic; }
public override void VisitLocal(ILocalSymbol symbol) { symbol.Type.Accept(this); }
private static bool IsPassedAsArgument(StatementSyntax statement, SemanticModel semanticModel, ILocalSymbol identitySymbol) { if (statement == null) return false; var args = statement.DescendantNodes().OfKind<ArgumentSyntax>(SyntaxKind.Argument); foreach (var arg in args) { var argSymbol = semanticModel.GetSymbolInfo(arg.Expression).Symbol; if (identitySymbol.Equals(argSymbol)) return true; } return false; }
private bool LocalsAreEquivalent(ILocalSymbol x, ILocalSymbol y) { return(HaveSameLocation(x, y)); }
private static bool IsDisposableLocalSymbol(ILocalSymbol localSymbol) { return(localSymbol != null && DisposableMemberInNonDisposableClass.ImplementsIDisposable(localSymbol.Type as INamedTypeSymbol)); }
public static ExpressionSyntax Visit(ExpressionSyntax initializer, ILocalSymbol local, SemanticModel semanticModel) { var simplifier = new InitializerRewriter(initializer, local, semanticModel); return (ExpressionSyntax)simplifier.Visit(initializer); }
/// <summary> /// Gets the annotated type of an ILocalSymbol. /// This has not yet been exposed on the public API. /// </summary> public static AnnotatedTypeSymbol GetAnnotatedType(this ILocalSymbol symbol) => new AnnotatedTypeSymbol(symbol.Type, symbol.NullableAnnotation);
public override void VisitLocal(ILocalSymbol symbol) { base.VisitLocal(symbol); }
protected abstract TLocalDeclarationStatementSyntax GetUpdatedLocalDeclarationStatement(SyntaxGenerator generator, TLocalDeclarationStatementSyntax localDeclarationStatement, ILocalSymbol symbol);
private int CombineHashCodes(ILocalSymbol x, int currentHash) { return(Hash.Combine(x.Locations.FirstOrDefault(), currentHash)); }
private static bool IsReturned(ILocalSymbol symbol, BlockSyntax block, SemanticModel semanticModel, CancellationToken cancellationToken) { using (var pooled = ReturnValueWalker.Create(block, Search.TopLevel, semanticModel, cancellationToken)) { foreach (var value in pooled.Item) { var returnedSymbol = semanticModel.GetSymbolSafe(value, cancellationToken); if (SymbolComparer.Equals(symbol, returnedSymbol)) { return(true); } if (value is ObjectCreationExpressionSyntax objectCreation) { if (objectCreation.ArgumentList != null) { foreach (var argument in objectCreation.ArgumentList.Arguments) { var arg = semanticModel.GetSymbolSafe(argument.Expression, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } if (objectCreation.Initializer != null) { foreach (var argument in objectCreation.Initializer.Expressions) { var arg = semanticModel.GetSymbolSafe(argument, cancellationToken); if (SymbolComparer.Equals(symbol, arg)) { return(true); } } } } if (value is InvocationExpressionSyntax invocation) { if (returnedSymbol == KnownSymbol.RxDisposable.Create && invocation.ArgumentList != null && invocation.ArgumentList.Arguments.TryGetSingle(out ArgumentSyntax argument)) { var body = (argument.Expression as ParenthesizedLambdaExpressionSyntax)?.Body; using (var pooledInvocations = InvocationWalker.Create(body)) { foreach (var candidate in pooledInvocations.Item.Invocations) { if (Disposable.IsDisposing(candidate, symbol, semanticModel, cancellationToken)) { return(true); } } } } } } } return(false); }
public static IVariableDeclaration CreateVariableDeclaration(ILocalSymbol variable, IVariableInitializer initializer, SemanticModel semanticModel, SyntaxNode syntax) { return(CreateVariableDeclaration(ImmutableArray.Create(variable), initializer, semanticModel, syntax)); }
private static IEnumerable <int> GetAssignedIndexes(IEnumerable <StatementSyntax> statements, ILocalSymbol symbol, SemanticModel semanticModel) { foreach (var statement in statements) { var assignment = statement as AssignmentStatementSyntax; if (assignment == null) { yield break; } var invocation = assignment.Left as InvocationExpressionSyntax; if (invocation?.ArgumentList == null || invocation.ArgumentList.Arguments.Count != 1) { yield break; } var assignedSymbol = semanticModel.GetSymbolInfo(invocation.Expression).Symbol; if (!symbol.Equals(assignedSymbol)) { yield break; } var argument = invocation.ArgumentList.Arguments.First(); var index = GetConstantArgumentValue(argument, semanticModel); if (!index.HasValue) { yield break; } yield return(index.Value); } }
public sealed override void VisitLocal(ILocalSymbol symbol) { Visit(symbol.Type); Visit(symbol.ContainingSymbol); }
private async Task<IEnumerable<SymbolDisplayPart>> GetLocalPartsAsync(ILocalSymbol symbol) { if (symbol.IsConst) { var initializerParts = await GetInitializerSourcePartsAsync(symbol).ConfigureAwait(false); if (initializerParts != null) { var parts = ToMinimalDisplayParts(symbol, MinimallyQualifiedFormat).ToList(); parts.AddRange(Space()); parts.AddRange(Punctuation("=")); parts.AddRange(Space()); parts.AddRange(initializerParts); return parts; } } return ToMinimalDisplayParts(symbol, MinimallyQualifiedFormatWithConstants); }
private static SyntaxNode CreateRootAddingDisposeToEndOfMethod(SyntaxNode root, ExpressionStatementSyntax statement, ILocalSymbol identitySymbol) { var method = statement.FirstAncestorOrSelf <MethodDeclarationSyntax>(); var newDispose = ImplementsDisposableExplicitly(identitySymbol.Type) ? SyntaxFactory.ExpressionStatement(SyntaxFactory.InvocationExpression( SyntaxFactory.MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression, SyntaxFactory.ParenthesizedExpression(SyntaxFactory.CastExpression(SyntaxFactory.ParseName("System.IDisposable").WithAdditionalAnnotations(Simplifier.Annotation), SyntaxFactory.IdentifierName(identitySymbol.Name))), SyntaxFactory.IdentifierName("Dispose")))) : SyntaxFactory.ParseStatement($"{identitySymbol.Name}.Dispose();"); newDispose = newDispose.WithAdditionalAnnotations(Formatter.Annotation); var last = method.Body.Statements.Last(); var newRoot = root.InsertNodesAfter(method.Body.Statements.Last(), new[] { newDispose }); return(newRoot); }
public override void VisitLocal(ILocalSymbol symbol) { VisitAttributes(symbol); symbol.Type.Accept(this); }
private static bool IsAssignedToField(ExpressionStatementSyntax expressionStatement, SemanticModel semanticModel, ILocalSymbol identitySymbol) { if (expressionStatement == null) return false; if (!expressionStatement.Expression.IsKind(SyntaxKind.SimpleAssignmentExpression)) return false; var assignment = (AssignmentExpressionSyntax)expressionStatement.Expression; var assignmentTarget = semanticModel.GetSymbolInfo(assignment.Left).Symbol; if (assignmentTarget?.Kind != SymbolKind.Field) return false; var assignmentSource = semanticModel.GetSymbolInfo(assignment.Right).Symbol; return (identitySymbol.Equals(assignmentSource)); }
private void AnalyzeSyntaxNode(SyntaxNodeAnalysisContext context) { if (GeneratedCodeAnalyzer?.IsGeneratedCode(context) == true) { return; } var catchClause = (CatchClauseSyntax)context.Node; if (catchClause.Declaration == null || catchClause.Block == null) { return; } ILocalSymbol symbol = context .SemanticModel .GetDeclaredSymbol(catchClause.Declaration, context.CancellationToken); if (symbol != null) { foreach (SyntaxNode node in catchClause.Block.DescendantNodes(f => !f.IsKind(SyntaxKind.CatchClause))) { if (node.IsKind(SyntaxKind.ThrowStatement)) { var throwStatement = (ThrowStatementSyntax)node; if (throwStatement.Expression != null) { ISymbol expressionSymbol = context .SemanticModel .GetSymbolInfo(throwStatement.Expression, context.CancellationToken) .Symbol; if (expressionSymbol != null && symbol.Equals(expressionSymbol)) { context.ReportDiagnostic( DiagnosticDescriptors.RemoveOriginalExceptionFromThrowStatement, throwStatement.Expression.GetLocation()); } } } } } if (catchClause.Declaration.Type != null && catchClause.Block.Statements.Count == 0) { ITypeSymbol typeSymbol = context .SemanticModel .GetTypeInfo(catchClause.Declaration.Type, context.CancellationToken) .Type; if (typeSymbol != null) { INamedTypeSymbol exceptionTypeSymbol = context.GetTypeByMetadataName("System.Exception"); if (typeSymbol.Equals(exceptionTypeSymbol)) { context.ReportDiagnostic( DiagnosticDescriptors.AvoidEmptyCatchClauseThatCatchesSystemException, catchClause.CatchKeyword.GetLocation()); } } } }
string GetLocalVariableMarkup (ILocalSymbol local) { if (local == null) throw new ArgumentNullException ("local"); var result = new StringBuilder (); if (local.IsConst) result.Append (Highlight ("const ", colorStyle.KeywordModifiers)); result.Append (GetTypeReferenceString (local.Type)); if (BreakLineAfterReturnType) { result.AppendLine (); } else { result.Append (" "); } result.Append (FilterEntityName (local.Name)); if (local.IsConst) { if (options.GetOption (CSharpFormattingOptions.SpacingAroundBinaryOperator) == BinaryOperatorSpacingOptions.Single) { result.Append (" = "); } else { result.Append ("="); } AppendConstant (result, local.Type, local.ConstantValue); } return result.ToString (); }
private static bool IsEndingWithDispose(SemanticModel semanticModel, List <StatementSyntax> insideUsing, ILocalSymbol disposableLocal) { var lastInUsingAsCall = (((insideUsing.LastOrDefault() as ExpressionStatementSyntax)?.Expression as InvocationExpressionSyntax)?.Expression as MemberAccessExpressionSyntax); if (lastInUsingAsCall == null) { return(false); } var targetSymbol = semanticModel.GetSymbolInfo(lastInUsingAsCall.Expression); if (!disposableLocal.Equals(targetSymbol.Symbol)) { return(false); } var dispose = semanticModel.Compilation.GetSpecialType(SpecialType.System_IDisposable).GetMembers("Dispose").Single(); var calledMethod = semanticModel.GetSymbolInfo(lastInUsingAsCall).Symbol; if (!dispose.Equals(calledMethod)) { return(false); } return(true); }
private async Task AddDescriptionForLocalAsync(ILocalSymbol symbol) { var parts = await GetLocalPartsAsync(symbol).ConfigureAwait(false); AddToGroup(SymbolDescriptionGroups.MainDescription, symbol.IsConst ? Description(FeaturesResources.local_constant) : Description(FeaturesResources.local_variable), parts); }
private static void ReduceUsingBlock(SemanticModel semanticModel, List <StatementSyntax> insideUsing, ILocalSymbol symbol) { for (int i = insideUsing.Count - 1; i >= 0; i--) { var flow = semanticModel.AnalyzeDataFlow(insideUsing[i]); if (flow.ReadInside.Contains(symbol) || flow.WrittenInside.Contains(symbol)) { break; } insideUsing.RemoveAt(i); } }
public sealed override void Initialize(AnalysisContext context) { context.RegisterOperationBlockStartAction( (operationBlockContext) => { if (operationBlockContext.OwningSymbol is IMethodSymbol containingMethod) { HashSet <ILocalSymbol> mightBecomeConstLocals = new HashSet <ILocalSymbol>(); HashSet <ILocalSymbol> assignedToLocals = new HashSet <ILocalSymbol>(); operationBlockContext.RegisterOperationAction( (operationContext) => { if (operationContext.Operation is IAssignmentOperation assignment) { AssignTo(assignment.Target, assignedToLocals, mightBecomeConstLocals); } else if (operationContext.Operation is IIncrementOrDecrementOperation increment) { AssignTo(increment.Target, assignedToLocals, mightBecomeConstLocals); } else { throw TestExceptionUtilities.UnexpectedValue(operationContext.Operation); } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment, OperationKind.Increment); operationBlockContext.RegisterOperationAction( (operationContext) => { IInvocationOperation invocation = (IInvocationOperation)operationContext.Operation; foreach (IArgumentOperation argument in invocation.Arguments) { if (argument.Parameter.RefKind == RefKind.Out || argument.Parameter.RefKind == RefKind.Ref) { AssignTo(argument.Value, assignedToLocals, mightBecomeConstLocals); } } }, OperationKind.Invocation); operationBlockContext.RegisterOperationAction( (operationContext) => { IVariableDeclarationGroupOperation declaration = (IVariableDeclarationGroupOperation)operationContext.Operation; foreach (IVariableDeclaratorOperation variable in declaration.Declarations.SelectMany(decl => decl.Declarators)) { ILocalSymbol local = variable.Symbol; if (!local.IsConst && !assignedToLocals.Contains(local)) { var localType = local.Type; if ((!localType.IsReferenceType || localType.SpecialType == SpecialType.System_String) && localType.SpecialType != SpecialType.None) { IVariableInitializerOperation initializer = variable.GetVariableInitializer(); if (initializer != null && initializer.Value.ConstantValue.HasValue) { mightBecomeConstLocals.Add(local); } } } } }, OperationKind.VariableDeclarationGroup); operationBlockContext.RegisterOperationBlockEndAction( (operationBlockEndContext) => { foreach (ILocalSymbol couldBeConstLocal in mightBecomeConstLocals) { Report(operationBlockEndContext, couldBeConstLocal, LocalCouldBeConstDescriptor); } }); } }); }
public sealed override void Initialize(AnalysisContext context) { context.RegisterCompilationStartAction( (compilationContext) => { Dictionary <IFieldSymbol, HashSet <INamedTypeSymbol> > fieldsSourceTypes = new Dictionary <IFieldSymbol, HashSet <INamedTypeSymbol> >(); compilationContext.RegisterOperationBlockStartAction( (operationBlockContext) => { if (operationBlockContext.OwningSymbol is IMethodSymbol containingMethod) { Dictionary <ILocalSymbol, HashSet <INamedTypeSymbol> > localsSourceTypes = new Dictionary <ILocalSymbol, HashSet <INamedTypeSymbol> >(); // Track explicit assignments. operationBlockContext.RegisterOperationAction( (operationContext) => { if (operationContext.Operation is IAssignmentOperation assignment) { AssignTo(assignment.Target, localsSourceTypes, fieldsSourceTypes, assignment.Value); } else if (operationContext.Operation is IIncrementOrDecrementOperation increment) { SyntaxNode syntax = increment.Syntax; ITypeSymbol type = increment.Type; Optional <object> constantValue = new Optional <object>(1); bool isImplicit = increment.IsImplicit; var value = new LiteralOperation(operationContext.Compilation.GetSemanticModel(syntax.SyntaxTree), syntax, type, constantValue, isImplicit); AssignTo(increment.Target, localsSourceTypes, fieldsSourceTypes, value); } else { throw TestExceptionUtilities.UnexpectedValue(operationContext.Operation); } }, OperationKind.SimpleAssignment, OperationKind.CompoundAssignment, OperationKind.Increment); // Track arguments that match out or ref parameters. operationBlockContext.RegisterOperationAction( (operationContext) => { IInvocationOperation invocation = (IInvocationOperation)operationContext.Operation; foreach (IArgumentOperation argument in invocation.Arguments) { if (argument.Parameter.RefKind == RefKind.Out || argument.Parameter.RefKind == RefKind.Ref) { AssignTo(argument.Value, localsSourceTypes, fieldsSourceTypes, argument.Parameter.Type); } } }, OperationKind.Invocation); // Track local variable initializations. operationBlockContext.RegisterOperationAction( (operationContext) => { IVariableInitializerOperation initializer = (IVariableInitializerOperation)operationContext.Operation; // If the parent is a single variable declaration, just process that one variable. If it's a multi variable // declaration, process all variables being assigned if (initializer.Parent is IVariableDeclaratorOperation singleVariableDeclaration) { ILocalSymbol local = singleVariableDeclaration.Symbol; AssignTo(local, local.Type, localsSourceTypes, initializer.Value); } else if (initializer.Parent is IVariableDeclarationOperation multiVariableDeclaration) { foreach (ILocalSymbol local in multiVariableDeclaration.GetDeclaredVariables()) { AssignTo(local, local.Type, localsSourceTypes, initializer.Value); } } }, OperationKind.VariableInitializer); // Report locals that could have more specific types. operationBlockContext.RegisterOperationBlockEndAction( (operationBlockEndContext) => { foreach (ILocalSymbol local in localsSourceTypes.Keys) { if (HasMoreSpecificSourceType(local, local.Type, localsSourceTypes, out var mostSpecificSourceType)) { Report(operationBlockEndContext, local, mostSpecificSourceType, LocalCouldHaveMoreSpecificTypeDescriptor); } } }); } }); // Track field initializations. compilationContext.RegisterOperationAction( (operationContext) => { IFieldInitializerOperation initializer = (IFieldInitializerOperation)operationContext.Operation; foreach (IFieldSymbol initializedField in initializer.InitializedFields) { AssignTo(initializedField, initializedField.Type, fieldsSourceTypes, initializer.Value); } }, OperationKind.FieldInitializer); // Report fields that could have more specific types. compilationContext.RegisterCompilationEndAction( (compilationEndContext) => { foreach (IFieldSymbol field in fieldsSourceTypes.Keys) { if (HasMoreSpecificSourceType(field, field.Type, fieldsSourceTypes, out var mostSpecificSourceType)) { Report(compilationEndContext, field, mostSpecificSourceType, FieldCouldHaveMoreSpecificTypeDescriptor); } } }); }); }
/// <summary> /// Retrieve a local slot by its symbol. /// </summary> internal LocalDefinition GetLocal(ILocalSymbol symbol) { return(LocalMap[symbol]); }
public VariableDeclaration(ILocalSymbol variable, IExpression initialValue, SyntaxNode syntax) { Variable = variable; InitialValue = initialValue; Syntax = syntax; }
public virtual void VisitLocal(ILocalSymbol symbol) { DefaultVisit(symbol); }
private static string GetClassificationForLocal(ILocalSymbol localSymbol) { return(localSymbol.IsConst ? ClassificationTypeNames.ConstantName : ClassificationTypeNames.LocalName); }
private static bool TryAnalyze( SemanticModel semanticModel, ILocalSymbol local, TypeSyntax typeNode, SyntaxToken identifier, Conversion conversion, SyntaxNode searchScope, [NotNullWhen(true)] out INamedTypeSymbol?tupleType, out ImmutableArray <MemberAccessExpressionSyntax> memberAccessExpressions, CancellationToken cancellationToken) { tupleType = null; memberAccessExpressions = default; if (identifier.IsMissing) { return(false); } if (!IsViableTupleTypeSyntax(typeNode)) { return(false); } if (conversion.Exists && !conversion.IsIdentity && !conversion.IsTupleConversion && !conversion.IsTupleLiteralConversion) { // If there is any other conversion, we bail out because the source type might not be a tuple // or it is a tuple but only thanks to target type inference, which won't occur in a deconstruction. // Interesting case that illustrates this is initialization with a default literal: // (int a, int b) t = default; // This is classified as conversion.IsNullLiteral. return(false); } var type = semanticModel.GetTypeInfo(typeNode, cancellationToken).Type; if (type == null || !type.IsTupleType) { return(false); } tupleType = (INamedTypeSymbol)type; if (tupleType.TupleElements.Length < 2) { return(false); } // All tuple elements must have been explicitly provided by the user. foreach (var element in tupleType.TupleElements) { if (element.IsImplicitlyDeclared) { return(false); } } using var _ = ArrayBuilder <MemberAccessExpressionSyntax> .GetInstance(out var references); // If the user actually uses the tuple local for anything other than accessing // fields off of it, then we can't deconstruct this tuple into locals. if (!OnlyUsedToAccessTupleFields( semanticModel, searchScope, local, references, cancellationToken)) { return(false); } // Can only deconstruct the tuple if the names we introduce won't collide // with anything else in scope (either outside, or inside the method). if (AnyTupleFieldNamesCollideWithExistingNames( semanticModel, tupleType, searchScope, cancellationToken)) { return(false); } memberAccessExpressions = references.ToImmutable(); return(true); }
public override void VisitLocal(ILocalSymbol symbol) { if (format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeType)) { symbol.Type.Accept(this); AddSpace(); } builder.Add(CreatePart(SymbolDisplayPartKind.LocalName, symbol, symbol.Name)); if (symbol.IsConst && symbol.HasConstantValue && format.LocalOptions.IncludesOption(SymbolDisplayLocalOptions.IncludeConstantValue) && CanAddConstant(symbol.Type, symbol.ConstantValue)) { AddSpace(); AddPunctuation(SyntaxKind.EqualsToken); AddSpace(); AddConstantValue(symbol.Type, symbol.ConstantValue); } }
protected override bool CanMoveToBlock(ILocalSymbol localSymbol, SyntaxNode currentBlock, SyntaxNode destinationBlock) => localSymbol.CanSafelyMoveLocalToBlock(currentBlock, destinationBlock);
private void Report(OperationBlockAnalysisContext context, ILocalSymbol local, DiagnosticDescriptor descriptor) { context.ReportDiagnostic(Diagnostic.Create(descriptor, local.Locations.FirstOrDefault())); }
private bool LocalsAreEquivalent(ILocalSymbol x, ILocalSymbol y) { return HaveSameLocation(x, y); }
private static IEnumerable<int> GetAssignedIndexes(IEnumerable<StatementSyntax> statements, ILocalSymbol symbol, SemanticModel semanticModel) { foreach (var statement in statements) { var assignment = statement as AssignmentStatementSyntax; if (assignment == null) { yield break; } var invocation = assignment.Left as InvocationExpressionSyntax; if (invocation?.ArgumentList == null || invocation.ArgumentList.Arguments.Count != 1) { yield break; } var assignedSymbol = semanticModel.GetSymbolInfo(invocation.Expression).Symbol; if (!symbol.Equals(assignedSymbol)) { yield break; } var argument = invocation.ArgumentList.Arguments.First(); var index = GetConstantArgumentValue(argument, semanticModel); if (!index.HasValue) { yield break; } yield return index.Value; } }
private LoopDeclarationVerifier(ForStatementSyntax forStatement, SemanticModel semanticModel, ILocalSymbol loopIndex) { _forStatement = forStatement; _semanticModel = semanticModel; _loopIndex = loopIndex; }
private static bool IsReturned(MethodDeclarationSyntax method, StatementSyntax statement, SemanticModel semanticModel, ILocalSymbol identitySymbol) { var anonymousFunction = statement.FirstAncestorOfKind(SyntaxKind.ParenthesizedLambdaExpression, SyntaxKind.SimpleLambdaExpression, SyntaxKind.AnonymousMethodExpression) as AnonymousFunctionExpressionSyntax; IMethodSymbol methodSymbol; BlockSyntax body; if (anonymousFunction != null) { methodSymbol = semanticModel.GetSymbolInfo(anonymousFunction).Symbol as IMethodSymbol; body = anonymousFunction.Body as BlockSyntax; } else { methodSymbol = semanticModel.GetDeclaredSymbol(method); body = method.Body; } if (body == null) return true; var returnExpressions = body.DescendantNodes().OfType<ReturnStatementSyntax>().Select(r => r.Expression); var returnTypeSymbol = methodSymbol?.ReturnType; if (returnTypeSymbol == null) return false; if (returnTypeSymbol.SpecialType == SpecialType.System_Void) return false; var isReturning = returnExpressions.Any(returnExpression => { var returnSymbol = semanticModel.GetSymbolInfo(returnExpression).Symbol; if (returnSymbol == null) return false; return returnSymbol.Equals(identitySymbol); }); return isReturning; }
public override bool VisitLocal(ILocalSymbol symbol) { return(Visit(symbol.Type)); }
private static bool IsCorrectDispose(ExpressionStatementSyntax expressionStatement, SemanticModel semanticModel, ILocalSymbol identitySymbol) { if (expressionStatement == null) return false; var invocation = expressionStatement.Expression as InvocationExpressionSyntax; if (invocation?.ArgumentList.Arguments.Any() ?? true) return false; var memberAccess = invocation.Expression as MemberAccessExpressionSyntax; if (memberAccess == null) return false; ISymbol memberSymbol; if (memberAccess.Expression.IsKind(SyntaxKind.IdentifierName)) { memberSymbol = semanticModel.GetSymbolInfo(memberAccess.Expression).Symbol; } else if (memberAccess.Expression.IsKind(SyntaxKind.ParenthesizedExpression)) { var parenthesizedExpression = (ParenthesizedExpressionSyntax)memberAccess.Expression; var cast = parenthesizedExpression.Expression as CastExpressionSyntax; if (cast == null) return false; var catTypeSymbol = semanticModel.GetTypeInfo(cast.Type).Type; if (catTypeSymbol.SpecialType != SpecialType.System_IDisposable) return false; memberSymbol = semanticModel.GetSymbolInfo(cast.Expression).Symbol; } else return false; if (memberSymbol == null || !memberSymbol.Equals(identitySymbol)) return false; var memberAccessed = memberAccess.Name as IdentifierNameSyntax; if (memberAccessed == null) return false; if (memberAccessed.Identifier.Text != "Dispose" || memberAccessed.Arity != 0) return false; var methodSymbol = semanticModel.GetSymbolInfo(memberAccessed).Symbol as IMethodSymbol; if (methodSymbol == null) return false; if (methodSymbol.ToString() == "System.IDisposable.Dispose()") return true; var disposeMethod = (IMethodSymbol)semanticModel.Compilation.GetSpecialType(SpecialType.System_IDisposable).GetMembers("Dispose").Single(); var isDispose = methodSymbol.Equals(methodSymbol.ContainingType.FindImplementationForInterfaceMember(disposeMethod)); return isDispose; }
private static void GetInterfaceInfo( SemanticModel model, ILocalSymbol foreachVariable, IOperation foreachCollection, out ITypeSymbol explicitCastInterface, out string collectionNameSuggestion, out string countName ) { explicitCastInterface = null; collectionNameSuggestion = null; countName = null; // go through list of types and interfaces to find out right set; var foreachType = foreachVariable.Type; if (IsNullOrErrorType(foreachType)) { return; } var collectionType = foreachCollection.Type; if (IsNullOrErrorType(collectionType)) { return; } // go through explicit types first. // check array case if (collectionType is IArrayTypeSymbol array) { if (array.Rank != 1) { // array type supports IList and other interfaces, but implementation // only supports Rank == 1 case. other case, it will throw on runtime // even if there is no error on compile time. // we explicitly mark that we only support Rank == 1 case return; } if (!IsExchangable(array.ElementType, foreachType, model.Compilation)) { return; } collectionNameSuggestion = "array"; explicitCastInterface = null; countName = Length; return; } // check string case if (collectionType.SpecialType == SpecialType.System_String) { var charType = model.Compilation.GetSpecialType(SpecialType.System_Char); if (!IsExchangable(charType, foreachType, model.Compilation)) { return; } collectionNameSuggestion = "str"; explicitCastInterface = null; countName = Length; return; } // check ImmutableArray case if ( collectionType.OriginalDefinition.Equals( model.Compilation.GetTypeByMetadataName(typeof(ImmutableArray <>).FullName) ) ) { var indexer = GetInterfaceMember(collectionType, get_Item); if (indexer != null) { if (!IsExchangable(indexer.ReturnType, foreachType, model.Compilation)) { return; } collectionNameSuggestion = "array"; explicitCastInterface = null; countName = Length; return; } } // go through all known interfaces we support next. var knownCollectionInterfaces = s_KnownInterfaceNames .Select(s => model.Compilation.GetTypeByMetadataName(s)) .Where(t => !IsNullOrErrorType(t)); // for all interfaces, we suggest collection name as "list" collectionNameSuggestion = "list"; // check type itself is interface case if ( collectionType.TypeKind == TypeKind.Interface && knownCollectionInterfaces.Contains(collectionType.OriginalDefinition) ) { var indexer = GetInterfaceMember(collectionType, get_Item); if ( indexer != null && IsExchangable(indexer.ReturnType, foreachType, model.Compilation) ) { explicitCastInterface = null; countName = Count; return; } } // check regular cases (implicitly implemented) ITypeSymbol explicitInterface = null; foreach (var current in collectionType.AllInterfaces) { if (!knownCollectionInterfaces.Contains(current.OriginalDefinition)) { continue; } // see how the type implements the interface var countSymbol = GetInterfaceMember(current, get_Count); var indexerSymbol = GetInterfaceMember(current, get_Item); if (countSymbol == null || indexerSymbol == null) { continue; } if ( !( collectionType.FindImplementationForInterfaceMember(countSymbol) is IMethodSymbol countImpl ) || !( collectionType.FindImplementationForInterfaceMember(indexerSymbol) is IMethodSymbol indexerImpl ) ) { continue; } if (!IsExchangable(indexerImpl.ReturnType, foreachType, model.Compilation)) { continue; } // implicitly implemented! if ( countImpl.ExplicitInterfaceImplementations.IsEmpty && indexerImpl.ExplicitInterfaceImplementations.IsEmpty ) { explicitCastInterface = null; countName = Count; return; } if (explicitInterface == null) { explicitInterface = current; } } // okay, we don't have implicitly implemented one, but we do have explicitly implemented one if (explicitInterface != null) { explicitCastInterface = explicitInterface; countName = Count; } }
private static bool IsReturned(MethodDeclarationSyntax method, SemanticModel semanticModel, ILocalSymbol identitySymbol) { var returnTypeSymbol = semanticModel.GetTypeInfo(method.ReturnType).Type; if (returnTypeSymbol == null) return false; if (returnTypeSymbol.SpecialType == SpecialType.System_Void || !returnTypeSymbol.Equals(identitySymbol.Type)) return false; var returns = method.Body.DescendantNodes().OfType<ReturnStatementSyntax>(); var isReturning = returns.Any(r => { var returnSymbol = semanticModel.GetSymbolInfo(r.Expression).Symbol; if (returnSymbol == null) return false; return returnSymbol.Equals(identitySymbol); }); return isReturning; }
protected abstract bool IsSupported( ILocalSymbol foreachVariable, IForEachLoopOperation forEachOperation, TForEachStatement foreachStatement );
private InitializerRewriter(ExpressionSyntax initializer, ILocalSymbol localSymbol, SemanticModel semanticModel) { _semanticModel = semanticModel; _localSymbol = localSymbol; _initializer = initializer; }
private async Task <ImmutableArray <SymbolDisplayPart> > GetLocalPartsAsync(ILocalSymbol symbol) { if (symbol.IsConst) { var initializerParts = await GetInitializerSourcePartsAsync(symbol).ConfigureAwait(false); if (initializerParts != null) { var parts = ArrayBuilder <SymbolDisplayPart> .GetInstance(); parts.AddRange(ToMinimalDisplayParts(symbol, MinimallyQualifiedFormat)); parts.AddRange(Space()); parts.AddRange(Punctuation("=")); parts.AddRange(Space()); parts.AddRange(initializerParts); return(parts.ToImmutableAndFree()); } } return(ToMinimalDisplayParts(symbol, MinimallyQualifiedFormatWithConstants)); }
public override object VisitLocal(ILocalSymbol localSymbol) { WriteType(SymbolKeyType.BodyLevel); BodyLevelSymbolKey.Create(localSymbol, this); return(null); }
private async Task<ImmutableArray<SymbolDisplayPart>> GetLocalPartsAsync(ILocalSymbol symbol) { if (symbol.IsConst) { var initializerParts = await GetInitializerSourcePartsAsync(symbol).ConfigureAwait(false); if (initializerParts != null) { var parts = ArrayBuilder<SymbolDisplayPart>.GetInstance(); parts.AddRange(ToMinimalDisplayParts(symbol, MinimallyQualifiedFormat)); parts.AddRange(Space()); parts.AddRange(Punctuation("=")); parts.AddRange(Space()); parts.AddRange(initializerParts); return parts.ToImmutableAndFree(); } } return ToMinimalDisplayParts(symbol, MinimallyQualifiedFormatWithConstants); }
public RecursiveIsNewlyCreatedObjectState Add(ILocalSymbol variable) => new RecursiveIsNewlyCreatedObjectState(VariablesUnderTest.Add(variable));