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));
        }
예제 #2
0
 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);
        }
예제 #4
0
        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);
            }
예제 #9
0
        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));
        }