public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            Document document = context.Document;

            Microsoft.CodeAnalysis.Text.TextSpan textSpan = context.Span;
            CancellationToken cancellationToken           = context.CancellationToken;

            CompilationUnitSyntax root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false) as CompilationUnitSyntax;

            SemanticModel model = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            // if length is 0 then no particular range is selected, so pick the first enclosing member
            if (textSpan.Length == 0)
            {
                MemberDeclarationSyntax decl = root.FindToken(textSpan.Start).Parent.AncestorsAndSelf().OfType <MemberDeclarationSyntax>().FirstOrDefault();
                if (decl != null)
                {
                    textSpan = decl.FullSpan;
                }
            }

            IEnumerable <ExpandablePropertyInfo> properties = ExpansionChecker.GetExpandableProperties(textSpan, root, model);

            if (properties.Any())
            {
                CodeAction action = CodeAction.Create(
                    "Apply INotifyPropertyChanged pattern",
                    c => ImplementNotifyPropertyChangedAsync(document, root, model, properties, c),
                    equivalenceKey: nameof(ImplementNotifyPropertyChangedCodeRefactoringProvider));

                context.RegisterRefactoring(action);
            }
        }
예제 #2
0
        public static bool ShouldUseSmartTokenFormatterInsteadOfIndenter(
            IEnumerable <IFormattingRule> formattingRules,
            CompilationUnitSyntax root,
            TextLine line,
            OptionSet optionSet,
            CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(formattingRules);
            Contract.ThrowIfNull(root);

            //if (!optionSet.GetOption(FeatureOnOffOptions.AutoFormattingOnReturn, LanguageNames.CSharp))
            //{
            //    return false;
            //}

            if (optionSet.GetOption(FormattingOptions.SmartIndent, LanguageNames.CSharp) != FormattingOptions.IndentStyle.Smart)
            {
                return(false);
            }

            var firstNonWhitespacePosition = line.GetFirstNonWhitespacePosition();

            if (!firstNonWhitespacePosition.HasValue)
            {
                return(false);
            }

            var token = root.FindToken(firstNonWhitespacePosition.Value);

            if (token.IsKind(SyntaxKind.None) ||
                token.SpanStart != firstNonWhitespacePosition)
            {
                return(false);
            }

            // first see whether there is a line operation for current token
            var previousToken = token.GetPreviousToken(includeZeroWidth: true);

            // only use smart token formatter when we have two visible tokens.
            if (previousToken.Kind() == SyntaxKind.None || previousToken.IsMissing)
            {
                return(false);
            }

            var lineOperation = FormattingOperations.GetAdjustNewLinesOperation(formattingRules, previousToken, token, optionSet);

            if (lineOperation == null || lineOperation.Option == AdjustNewLinesOption.ForceLinesIfOnSingleLine)
            {
                // no indentation operation, nothing to do for smart token formatter
                return(false);
            }

            // We're pressing enter between two tokens, have the formatter figure out hte appropriate
            // indentation.
            return(true);
        }
예제 #3
0
        public static bool ShouldUseSmartTokenFormatterInsteadOfIndenter(
            IEnumerable <IFormattingRule> formattingRules,
            CompilationUnitSyntax root,
            ITextSnapshotLine line,
            OptionSet optionSet,
            CancellationToken cancellationToken)
        {
            Contract.ThrowIfNull(formattingRules);
            Contract.ThrowIfNull(root);
            Contract.ThrowIfNull(line);

            if (optionSet.GetOption(FormattingOptions.SmartIndent, LanguageNames.CSharp) != FormattingOptions.IndentStyle.Smart)
            {
                return(false);
            }

            var firstNonWhitespacePosition = line.GetFirstNonWhitespacePosition();

            if (!firstNonWhitespacePosition.HasValue)
            {
                return(false);
            }

            var token = root.FindToken(firstNonWhitespacePosition.Value);

            if (token.IsKind(SyntaxKind.None) ||
                token.SpanStart != firstNonWhitespacePosition)
            {
                return(false);
            }

            // first see whether there is a line operation for current token
            var previousToken = token.GetPreviousToken(includeZeroWidth: true);

            // only use smart token formatter when we have two visible tokens.
            if (previousToken.Kind() == SyntaxKind.None || previousToken.IsMissing)
            {
                return(false);
            }

            var lineOperation = FormattingOperations.GetAdjustNewLinesOperation(formattingRules, previousToken, token, optionSet);

            if (lineOperation != null)
            {
                return(true);
            }

            // no indentation operation, nothing to do for smart token formatter
            return(false);
        }
예제 #4
0
        private static void Analyze(SyntaxNodeAnalysisContext context)
        {
            CompilationUnitSyntax node = (CompilationUnitSyntax)context.Node;

            if (Helper.IsGeneratedCode(context) || Helper.IsAssemblyInfo(context) || Helper.HasAutoGeneratedComment(node))
            {
                return;
            }

            if (node.FindToken(0).IsKind(SyntaxKind.EndOfFileToken))
            {
                return;
            }

            var first = node.GetLeadingTrivia();

            if (!first.Any())
            {
                CreateDiagnostic(context, node.GetLocation());
                return;
            }

            SyntaxTrivia copyrightSyntax = first[0];

            if (first[0].IsKind(SyntaxKind.RegionDirectiveTrivia))
            {
                if (first.Count < 2 || !first[1].IsKind(SyntaxKind.SingleLineCommentTrivia))
                {
                    CreateDiagnostic(context, context.Node.GetLocation());
                    return;
                }
                copyrightSyntax = first[1];
            }

            bool isCorrectStatement = CheckCopyrightStatement(context, copyrightSyntax);

            if (!isCorrectStatement)
            {
                CreateDiagnostic(context, copyrightSyntax.GetLocation());
                return;
            }
        }
예제 #5
0
        /// <summary>
        /// Checks for the presence of an "autogenerated" comment in the starting trivia for a file
        /// The compiler generates a version of the AssemblyInfo.cs file for certain projects (not named AssemblyInfo.cs), and this is how to pick it up
        /// </summary>
        /// <param name="node"></param>
        /// <returns></returns>
        public static bool HasAutoGeneratedComment(CompilationUnitSyntax node)
        {
            if (node.FindToken(0).IsKind(SyntaxKind.EndOfFileToken))
            {
                return(false);
            }

            var first = node.GetLeadingTrivia();

            if (first.Count == 0)
            {
                return(false);
            }

            string possibleHeader = first.ToFullString();


            bool isAutogenerated = possibleHeader.Contains(@"<autogenerated />") || possibleHeader.Contains("<auto-generated");

            return(isAutogenerated);
        }
예제 #6
0
        bool UpdateSemanticModel()
        {
            try {
                _Document      = View.TextSnapshot.GetOpenDocumentInCurrentContextWithChanges();
                _SemanticModel = _Document.GetSemanticModelAsync().Result;
                _Compilation   = _SemanticModel.SyntaxTree.GetCompilationUnitRoot();
            }
            catch (NullReferenceException) {
                _Node        = null;
                _Token       = default;
                _Trivia      = default;
                _LineComment = default;
                return(false);
            }
            int pos = View.Selection.Start.Position;

            try {
                _Token = _Compilation.FindToken(pos, true);
            }
            catch (ArgumentOutOfRangeException) {
                _Node        = null;
                _Token       = default;
                _Trivia      = default;
                _LineComment = default;
                return(false);
            }
            var triviaList = _Token.HasLeadingTrivia ? _Token.LeadingTrivia : _Token.HasTrailingTrivia ? _Token.TrailingTrivia : default;

            if (triviaList.Equals(SyntaxTriviaList.Empty) == false && triviaList.FullSpan.Contains(pos))
            {
                _Trivia      = triviaList.FirstOrDefault(i => i.Span.Contains(pos));
                _LineComment = triviaList.FirstOrDefault(i => i.IsLineComment());
            }
            else
            {
                _Trivia = _LineComment = default;
            }
            _Node = _Compilation.FindNode(_Token.Span, true, true);
            return(true);
        }
        public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            Document document = context.Document;

            Microsoft.CodeAnalysis.Text.TextSpan textSpan = context.Span;
            CancellationToken cancellationToken           = context.CancellationToken;

            CompilationUnitSyntax root = (CompilationUnitSyntax)await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            SyntaxToken   token         = root.FindToken(textSpan.Start);
            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (token.Kind() == SyntaxKind.IdentifierToken &&
                token.Parent.Kind() == SyntaxKind.ClassDeclaration)
            {
                string className = token.Text;

                CreateEqualityCompareCodeAction action = new CreateEqualityCompareCodeAction($"Create EqualityCompare for {className}",
                                                                                             (c) => Task.FromResult(CreateEqualityCompareConverterForClass(document, semanticModel, token, root, c)));
                context.RegisterRefactoring(action);
            }
        }
        static DebugDataTipInfo GetInfo(CompilationUnitSyntax root, SemanticModel semanticModel, int position, CancellationToken cancellationToken)
        {
            var    token   = root.FindToken(position);
            string textOpt = null;

            var expression = token.Parent as ExpressionSyntax;

            if (expression == null)
            {
                if (Microsoft.CodeAnalysis.CSharpExtensions.IsKind(token, SyntaxKind.IdentifierToken))
                {
                    if (token.Parent is MethodDeclarationSyntax)
                    {
                        return(default(DebugDataTipInfo));
                    }
                    if (semanticModel != null)
                    {
                        if (token.Parent is PropertyDeclarationSyntax)
                        {
                            var propertySymbol = semanticModel.GetDeclaredSymbol((PropertyDeclarationSyntax)token.Parent);
                            if (propertySymbol.IsStatic)
                            {
                                textOpt = propertySymbol.ContainingType.GetFullName() + "." + propertySymbol.Name;
                            }
                        }
                        else if (token.GetAncestor <FieldDeclarationSyntax> () != null)
                        {
                            var fieldSymbol = semanticModel.GetDeclaredSymbol(token.GetAncestor <VariableDeclaratorSyntax> ());
                            if (fieldSymbol.IsStatic)
                            {
                                textOpt = fieldSymbol.ContainingType.GetFullName() + "." + fieldSymbol.Name;
                            }
                        }
                    }

                    return(new DebugDataTipInfo(token.Span, text: textOpt));
                }
                else
                {
                    return(default(DebugDataTipInfo));
                }
            }

            if (expression.IsAnyLiteralExpression())
            {
                // If the user hovers over a literal, give them a DataTip for the type of the
                // literal they're hovering over.
                // Partial semantics should always be sufficient because the (unconverted) type
                // of a literal can always easily be determined.
                var type = semanticModel?.GetTypeInfo(expression, cancellationToken).Type;
                return(type == null
                                        ? default(DebugDataTipInfo)
                                                : new DebugDataTipInfo(expression.Span, type.GetFullName()));
            }

            // Check if we are invoking method and if we do return null so we don't invoke it
            if (expression.Parent is InvocationExpressionSyntax ||
                (semanticModel != null &&
                 expression.Parent is MemberAccessExpressionSyntax &&
                 expression.Parent.Parent is InvocationExpressionSyntax &&
                 semanticModel.GetSymbolInfo(token).Symbol is IMethodSymbol))
            {
                return(default(DebugDataTipInfo));
            }

            if (expression.IsRightSideOfDotOrArrow())
            {
                var curr = expression;
                while (true)
                {
                    var conditionalAccess = curr.GetParentConditionalAccessExpression();
                    if (conditionalAccess == null)
                    {
                        break;
                    }

                    curr = conditionalAccess;
                }

                if (curr == expression)
                {
                    // NB: Parent.Span, not Span as below.
                    return(new DebugDataTipInfo(expression.Parent.Span, text: null));
                }

                // NOTE: There may not be an ExpressionSyntax corresponding to the range we want.
                // For example, for input a?.$$B?.C, we want span [|a?.B|]?.C.
                return(new DebugDataTipInfo(TextSpan.FromBounds(curr.SpanStart, expression.Span.End), text: null));
            }

            var typeSyntax = expression as TypeSyntax;

            if (typeSyntax != null && typeSyntax.IsVar)
            {
                // If the user is hovering over 'var', then pass back the full type name that 'var'
                // binds to.
                var type = semanticModel?.GetTypeInfo(typeSyntax, cancellationToken).Type;
                if (type != null)
                {
                    textOpt = type.GetFullName();
                }
            }

            if (semanticModel != null)
            {
                if (expression is IdentifierNameSyntax)
                {
                    if (expression.Parent is ObjectCreationExpressionSyntax)
                    {
                        textOpt = ((INamedTypeSymbol)semanticModel.GetSymbolInfo(expression).Symbol).GetFullName();
                    }
                    else if (expression.Parent is AssignmentExpressionSyntax && expression.Parent.Parent is InitializerExpressionSyntax)
                    {
                        var variable = expression.GetAncestor <VariableDeclaratorSyntax> ();
                        if (variable != null)
                        {
                            textOpt = variable.Identifier.Text + "." + ((IdentifierNameSyntax)expression).Identifier.Text;
                        }
                    }
                }
            }
            return(new DebugDataTipInfo(expression.Span, textOpt));
        }
예제 #9
0
파일: CiSnippets.cs 프로젝트: qmgindi/Au
    //static int s_test;
    public static void AddSnippets(List <CiComplItem> items, TextSpan span, CompilationUnitSyntax root, string code, CSharpSyntaxContext syncon)
    {
        //CSharpSyntaxContext was discovered later and therefore almost not used here.
        if (syncon.IsObjectCreationTypeContext)
        {
            return;
        }
        //CiUtil.GetContextType(syncon);

        //print.clear(); print.it(++s_test);

        //print.clear();
        //foreach (var v in root.ChildNodes()) {
        //	CiUtil.PrintNode(v);
        //}
        //print.it("---");

        _Context context = _Context.Unknown;
        int      pos     = span.Start;

        //get node from start
        var token = root.FindToken(pos);
        var node  = token.Parent;

        //CiUtil.PrintNode(node); //print.it("--");
        //return;

        //find ancestor/self that contains pos inside
        while (node != null && !node.Span.ContainsInside(pos))
        {
            node = node.Parent;
        }
        //CiUtil.PrintNode(node);
        //for(var v = node; v != null; v = v.Parent) print.it(v.GetType().Name, v is ExpressionSyntax, v is ExpressionStatementSyntax);

        //print.it(SyntaxFacts.IsTopLevelStatement);
        //print.it(SyntaxFacts.IsInNamespaceOrTypeContext); //not tested

        switch (node)
        {
        case BlockSyntax:
        case SwitchSectionSyntax:         //between case: and break;
        case ElseClauseSyntax:
        case LabeledStatementSyntax:
        case IfStatementSyntax s1 when pos > s1.CloseParenToken.SpanStart:
        case WhileStatementSyntax s2 when pos > s2.CloseParenToken.SpanStart:
        case DoStatementSyntax s3 when pos <s3.WhileKeyword.SpanStart:
                                        case ForStatementSyntax s4 when pos> s4.CloseParenToken.SpanStart:
        case CommonForEachStatementSyntax s5 when pos > s5.CloseParenToken.SpanStart:
        case LockStatementSyntax s6 when pos > s6.CloseParenToken.SpanStart:
        case FixedStatementSyntax s7 when pos > s7.CloseParenToken.SpanStart:
        case UsingStatementSyntax s8 when pos > s8.CloseParenToken.SpanStart:
            context = _Context.Function;
            break;

        case TypeDeclarationSyntax td when pos > td.OpenBraceToken.Span.Start:         //{ } of class, struct, interface
            context = _Context.Type;
            break;

        case NamespaceDeclarationSyntax ns when pos > ns.OpenBraceToken.Span.Start:
        case CompilationUnitSyntax:
        case null:
            context = _Context.Namespace | _Context.Function;             //Function for C# 9 top-level statements. //FUTURE: only if in correct place.
            break;

        case LambdaExpressionSyntax:
        case ArrowExpressionClauseSyntax:         //like void F() =>here
            context = _Context.Arrow;
            break;

        case AttributeListSyntax:
            context = _Context.Attributes;
            break;

        default:
            if (span.IsEmpty)               //if '=> here;' or '=> here)' etc, use =>
            {
                var t2 = token.GetPreviousToken();
                if (t2.IsKind(SyntaxKind.EqualsGreaterThanToken) && t2.Parent is LambdaExpressionSyntax)
                {
                    context = _Context.Arrow;
                }
            }
            break;
        }
        //print.it(context);
        s_context = context;

        if (s_items == null)
        {
            var a = new List <_CiComplItemSnippet>();
            if (!filesystem.exists(CustomFile).File)
            {
                try { filesystem.copy(folders.ThisAppBS + @"Default\Snippets2.xml", CustomFile); }
                catch { goto g1; }
            }
            _LoadFile(CustomFile, true);
            g1 : _LoadFile(DefaultFile, false);
            if (a.Count == 0)
            {
                return;
            }
            s_items = a;

            void _LoadFile(string file, bool custom)
            {
                try {
                    var xroot = XmlUtil.LoadElem(file);
                    foreach (var xg in xroot.Elements("group"))
                    {
                        if (!xg.Attr(out string sc, "context"))
                        {
                            continue;
                        }
                        _Context con = default;
                        if (sc == "Function")
                        {
                            con = _Context.Function;   //many
                        }
                        else                           //few, eg Type or Namespace|Type
                        {
                            foreach (var seg in sc.Segments("|"))
                            {
                                switch (sc[seg.Range])
                                {
                                case "Function": con |= _Context.Function; break;

                                case "Type": con |= _Context.Type; break;

                                case "Namespace": con |= _Context.Namespace; break;

                                case "Arrow": con |= _Context.Arrow; break;

                                case "Attributes": con |= _Context.Attributes; break;

                                case "Any": con |= _Context.Any; break;

                                case "Line": con |= _Context.Line; break;
                                }
                            }
                        }
                        if (con == default)
                        {
                            continue;
                        }
                        foreach (var xs in xg.Elements("snippet"))
                        {
                            a.Add(new _CiComplItemSnippet(xs.Attr("name"), xs, con, custom));
                        }
                    }
                }
                catch (Exception ex) { print.it("Failed to load snippets from " + file + "\r\n\t" + ex.ToStringWithoutStack()); }
            }

            //FUTURE: support $selection$. Add menu Edit -> Surround -> Snippet1|Snippet2|....
            //FUTURE: snippet editor, maybe like in Eclipse.
        }

        bool isLineStart = InsertCodeUtil.IsLineStart(code, pos);

        foreach (var v in s_items)
        {
            if (!v.context.HasAny(context))
            {
                continue;
            }
            if (v.context.Has(_Context.Line) && !isLineStart)
            {
                continue;
            }
            v.group   = 0; v.hidden = 0; v.hilite = 0; v.moveDown = 0;
            v.ci.Span = span;
            items.Add(v);
        }
    }