private static bool VariableIsNotUsedBeforePassedAsOutArgument(SemanticModel semanticModel, VariableDeclaratorSyntax variableDeclarator, ArgumentSyntax argument) { var firstStatement = variableDeclarator.FirstAncestorOrSelf <StatementSyntax>(); var lastStatement = argument.FirstAncestorOrSelf <StatementSyntax>().PrecedingSyblingOrSelf(); DataFlowAnalysis dataFlow; try { // TODO-IG: Implement a proprietary data flow analysis that will work over statements that do not have same parent. // The AnalyzeDataFlow() method will throw exception if the firstStatement and the lastStatement are // not within the same immediate parent statement. We have to implement a data flow analysis that will // accept statements that have a common root parent statement, but are not necessarily within the same // immediate parent statement. dataFlow = semanticModel.AnalyzeDataFlow(firstStatement, lastStatement); } catch { // TODO-IG: Remove the try-catch block once the data flow analysis is implemented. // At the moment, if the firstStatement and the lastStatement are not within the same immediate parent // we will simply assume that the variable is used, although this must not actually be the case. // Such cases will anyway appear rarely, so we can live with it so far. return(false); } var outVariableName = variableDeclarator.Identifier.ValueText; return(dataFlow.ReadInside.Union(dataFlow.WrittenInside).All(symbol => symbol.Name != outVariableName)); }
public override void VisitVariableDeclarator(VariableDeclaratorSyntax node) { if (node.Initializer != null) { AddDependentType(model.GetTypeInfo(node.Initializer.Value)); } else { AddDependentType(node.FirstAncestorOrSelf <VariableDeclarationSyntax>()?.Type); } base.VisitVariableDeclarator(node); }
private async Task <Document> DisposeFieldAsync(Document document, VariableDeclaratorSyntax variableDeclarator, CancellationToken cancellationToken) { var semanticModel = await document.GetSemanticModelAsync(cancellationToken); var type = variableDeclarator.FirstAncestorOrSelf <TypeDeclarationSyntax>(); var typeSymbol = semanticModel.GetDeclaredSymbol(type); var newTypeImplementingIDisposable = AddIDisposableImplementationToType(type, typeSymbol); var newTypeWithDisposeMethod = AddDisposeDeclarationToDisposeMethod(variableDeclarator, newTypeImplementingIDisposable, typeSymbol); var root = await document.GetSyntaxRootAsync(); var newRoot = root.ReplaceNode(type, newTypeWithDisposeMethod); var newDocument = document.WithSyntaxRoot(newRoot); return(newDocument); }
private static void HandleLocalVariable(SyntaxNodeAnalysisContext context, VariableDeclaratorSyntax variable) { if (context.SemanticModel.GetDeclaredSymbolSafe(variable, context.CancellationToken) is ILocalSymbol local) { var block = variable.FirstAncestorOrSelf <BlockSyntax>(); if (block == null) { return; } RefCounterStatus status = new RefCounterStatus(); AssignmentUtils.ProcessVariableInitialization(variable, block, context.SemanticModel, context.CancellationToken, status); ProcessLocalOrParamenterVar(context, local, block, status); } }
private static void AnalyzeFields(VariableDeclaratorSyntax declarator, Diagnostic diagnostic, SuppressionAnalysisContext context, SyntaxNode root) { var declarationSyntax = declarator.FirstAncestorOrSelf <FieldDeclarationSyntax>(); //suppress for fields that are not private and not static => statics cannot be set in editor and are not shown in the inspector and cannot be set there if (!declarationSyntax.Modifiers.Any(modifier => modifier.IsKind(SyntaxKind.PrivateKeyword) || modifier.IsKind(SyntaxKind.StaticKeyword)) && !declarationSyntax.AttributeLists.Any(attributeList => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == nameof(UnityEngine.HideInInspector)))) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); return; } //check for serializefield attribute => variable could be set in editor if (declarationSyntax.AttributeLists.Any(attributeList => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == nameof(UnityEngine.SerializeField)))) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); return; } var symbol = GetSymbol(diagnostic.Location.SourceTree, declarationSyntax.Declaration.Type, context); if (!symbol.Extends(typeof(UnityEngine.Object))) { return; } var methodBodies = MethodBodies(root) .ToList(); //check for valid assignments if (IsAssignedTo(declarator.Identifier.Text, methodBodies)) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); return; } //check for existence of this variable in any assigned property foreach (string variable in AssignedProperties(root, methodBodies)) { if (variable == declarator.Identifier.Text) { context.ReportSuppression(Suppression.Create(Rule, diagnostic)); } } }
private static IEnumerable<ITypeSymbol> ExtractTypesFromVariableDeclarator(VariableDeclaratorSyntax variable, SemanticModel model) { if (variable.Initializer != null) { var typeInfo = model.GetTypeInfo(variable.Initializer.Value); yield return typeInfo.Type; yield return typeInfo.ConvertedType; } else { var variableReturnType = variable.FirstAncestorOrSelf<VariableDeclarationSyntax>()?.Type; if (variableReturnType != null) { yield return model.GetSymbolInfo(variableReturnType).Symbol as ITypeSymbol; } } }
private Document Delete(Document document, VariableDeclaratorSyntax node) { var fieldDeclaration = node.FirstAncestorOrSelf<BaseFieldDeclarationSyntax>(); // If we won't have anything left, then just delete the whole declaration if (fieldDeclaration.Declaration.Variables.Count == 1) { return Delete(document, fieldDeclaration); } else { var newFieldDeclaration = fieldDeclaration.RemoveNode(node, SyntaxRemoveOptions.KeepNoTrivia); return document.ReplaceNodeAsync(fieldDeclaration, newFieldDeclaration, CancellationToken.None) .WaitAndGetResult_CodeModel(CancellationToken.None); } }
private VirtualTreePoint GetStartPoint(SourceText text, VariableDeclaratorSyntax node, EnvDTE.vsCMPart part) { var field = node.FirstAncestorOrSelf<BaseFieldDeclarationSyntax>(); int startPosition; switch (part) { case EnvDTE.vsCMPart.vsCMPartName: case EnvDTE.vsCMPart.vsCMPartAttributes: case EnvDTE.vsCMPart.vsCMPartHeader: case EnvDTE.vsCMPart.vsCMPartWhole: case EnvDTE.vsCMPart.vsCMPartBodyWithDelimiter: case EnvDTE.vsCMPart.vsCMPartHeaderWithAttributes: throw Exceptions.ThrowENotImpl(); case EnvDTE.vsCMPart.vsCMPartAttributesWithDelimiter: if (field.AttributeLists.Count == 0) { throw Exceptions.ThrowEFail(); } goto case EnvDTE.vsCMPart.vsCMPartWholeWithAttributes; case EnvDTE.vsCMPart.vsCMPartWholeWithAttributes: startPosition = field.SpanStart; break; case EnvDTE.vsCMPart.vsCMPartBody: throw Exceptions.ThrowEFail(); case EnvDTE.vsCMPart.vsCMPartNavigate: startPosition = node.Identifier.SpanStart; break; default: throw Exceptions.ThrowEInvalidArg(); } return new VirtualTreePoint(node.SyntaxTree, text, startPosition); }
public CodeRefactoring GetRefactoring(IDocument document, TextSpan textSpan, CancellationToken cancellationToken) { SyntaxNode root = (SyntaxNode)document.GetSyntaxRoot(cancellationToken); // If nothing selected, only cursor placed, increase the ending position by one if (textSpan.Length == 0) { textSpan = new TextSpan(textSpan.Start, 1); } // Get nodes for highlighted code IEnumerable <VariableDeclaratorSyntax> selectedNodes = root.DescendantNodes(textSpan).OfType <VariableDeclaratorSyntax>(); // Select the node that spans the selected text most // Note: Here I have reversed the ranges ! node.Span.Contains, not textSpan.Contains VariableDeclaratorSyntax selectedNode = null; int bestSpan = -1; foreach (var node in selectedNodes) { if (node.Span.Contains(textSpan)) { int spanWidth = node.Span.Intersection(textSpan).Value.Length; if (spanWidth > bestSpan) { bestSpan = spanWidth; selectedNode = node; } } } if (selectedNode == null) { return(null); } VariableDeclaratorSyntax declarator = selectedNode; // Verify does the variable declarator has value assigned if (declarator.Initializer == null || declarator.HasDiagnostics) { return(null); } ISemanticModel model = document.GetSemanticModel(cancellationToken); ISymbol declaredSymbol = model.GetDeclaredSymbol(declarator); LocalDeclarationStatementSyntax declarationStatement = declarator.FirstAncestorOrSelf <LocalDeclarationStatementSyntax>(); // Note: declarator might be within ForStatement, but cannot be inlined if (declarationStatement == null) { return(null); } var analysis = model.AnalyzeStatementDataFlow(declarationStatement); // Verify that the variable is never re-assigned if (analysis.WrittenOutside.Contains(declaredSymbol)) { return(null); } // Variable inlineing is not allowed if variable is never used (side effects never take place then!) if (!analysis.ReadOutside.Contains(declaredSymbol)) { return(null); } BlockSyntax block = declarationStatement.FirstAncestorOrSelf <BlockSyntax>(); if (block == null) { return(null); } // Verify that the variables used in declaration are not re-assigned within variable usage scope // Consider: // int a = 1; // int b = a; // int c = b; // a = 2; // int d = b; // `b' cannot be inlined because `d' would get other value // Note: ChildNodes instead of DescendantNodes, because it must not be any other (nested) block var blockAnalysis = model.AnalyzeStatementsDataFlow(declarationStatement, block.ChildNodes().OfType <StatementSyntax>().Last()); foreach (var initializerSymbol in model.AnalyzeExpressionDataFlow(declarator.Initializer.Value).ReadInside) { if (blockAnalysis.WrittenInside.Contains(initializerSymbol)) { return(null); } } return(new CodeRefactoring( new[] { new InlineLocalAction(document, declarator) } , declarator.Span)); }