none
CodeAction not firing up after CodeRefactoringProvider

    คำถาม

  • Hi,

    I have just started exploring Roslyn. I have created a sample app to auto close paranthesis, the functionality here is not that important instead, I am stuck up that my CodeAction method is not firing up while debugging.

    May be it's late here, I am missing something very basic or there is something else.

     [ExportCodeRefactoringProvider("DemoCodeRefactoring", LanguageNames.CSharp)]
        class CodeRefactoringProvider : ICodeRefactoringProvider
        {
            private readonly ICodeActionEditFactory editFactory;
    
            [ImportingConstructor]
            public CodeRefactoringProvider(ICodeActionEditFactory editFactory)
            {
                this.editFactory = editFactory;
            }
    
            public CodeRefactoring GetRefactoring(IDocument document, TextSpan textSpan, CancellationToken cancellationToken)
            {
                var syntaxTree = document.GetSyntaxTree(cancellationToken);
                var token = syntaxTree.Root.FindToken(textSpan.Start);
                if (token.Parent == null)
                {
                    return null;
                }
    
                if (token.Kind == (int)SyntaxKind.OpenParenToken)
                {
                    return new CodeRefactoring( new[] { new CodeAction(editFactory, document, token.Span) });
                }
    
                return null;
            }
        }

     public class CodeAction: ICodeAction
        {
            private Roslyn.Services.Editor.ICodeActionEditFactory editFactory;
            private Roslyn.Services.IDocument document;
            private Roslyn.Compilers.TextSpan textSpan;
            
            public CodeAction(Roslyn.Services.Editor.ICodeActionEditFactory editFactory, Roslyn.Services.IDocument document, Roslyn.Compilers.TextSpan textSpan)
            {
                this.editFactory = editFactory;
                this.document = document;
                this.textSpan = textSpan;
                Description = "Auto complete paran";
            }
    
            public string Description
            {
                get;
                private set;
            }
    
            public ICodeActionEdit GetEdit(System.Threading.CancellationToken cancellationToken)
            {
                var tree = (SyntaxTree)document.GetSyntaxTree(cancellationToken);
                var semanticModel = (SemanticModel)document.GetSemanticModel(cancellationToken);
    
                var token = tree.Root.FindToken(textSpan.Start);
                var nextToken = token.GetNextToken();
                
                var closeParanNode = Syntax.Token(SyntaxKind.CloseParenToken).Format();
    
                var newRoot = tree.Root.ReplaceToken(nextToken, closeParanNode);
                    
                return editFactory.CreateTreeTransformEdit(document.Project.Solution, tree, newRoot);
            }
    
            public System.Windows.Media.ImageSource Icon
            {
                get { return null; }
            }
        }
    Help Please!

    Adil Mughal (MCPD, MCT, MVP) - http://AdilMughal.com

    26 กุมภาพันธ์ 2555 19:08

ตอบทั้งหมด

  • Hi Adil,

    Does a breakpoint in your CodeRefactoringProvider ever get hit? If so, have you navigated to or selected an open paren? CodeRefactorings are contextual, based on the selection or location of the cursor.  If you want the code action to always appear, you should think about making it a CodeIssue instead.  Other than that, I don't see anything else wrong off the top of my head.  Note that you probably want to check for "!openParen.IsMissing && closeParen.IsMissing" before offering the refactoring - that is, that the open parenthesis actually exists, and the close parenthesis doesn't.


    -- Kevin Pilch-Bisson kevinpi@microsoft.com

    27 กุมภาพันธ์ 2555 5:18
  • Hi,

    Yes the breakpoint hit CodeRefactoringProvider, and enters to scope of condition when it found open paran in code, but never make it to CodeAction.

    Kinda confused as well. Will check again in a while and update. Please do tell me, if i am missing something.


    Adil Mughal (MCPD, MCT, MVP) - http://AdilMughal.com

    27 กุมภาพันธ์ 2555 6:04
  • That looks like it _should_ work.  The way that we display refactorings in Roslyn is through a smart tag.  If you hit Ctrl+. (Control and the period key), does the smart tag menu appear and display your refactoring?

    -- Kevin Pilch-Bisson kevinpi@microsoft.com

    27 กุมภาพันธ์ 2555 6:12
  • Hi,

    Your code runs fine for me, and I could trigger the GetEdit. It is very picky about when to show the refactoring, though, so maybe you'll want to increase the span a little if that's possible. When it does show up, it works fine if there are an open and close paren next to each other. It then simply removes the newline. However, if the close paren is missing, it throws an exception for me at the following line

    var newRoot = tree.Root.ReplaceToken(nextToken, closeParanNode);
    

    This is probably because you are replacing the token of a node with another kind of token (the CloseParenToken kind), and this is not allowed, I think. And maybe the exception doesn't show up for you for some reason, so it seems as if the whole action doesn't fire. Did you set a breakpoint at the start of the GetEdit method in your CodeAction? It should break there if you preview the refactoring.

    Also, the GetEdit does not trigger yet when the GetRefactoring triggers. The GetRefactoring only tells if there are refactorings available, and the GetEdit triggers when you want a preview or the result of that refactoring, so in that case your breakpoint won't hit until you preview the refactoring.

    Anyway, a solution to the exception would be to find out which types of node have an OpenParenToken and a CloseParenToken. Then find the type of the parent of your openParenToken, check which one it is, and then cast it to that type. Then you can either Update or Repace the CloseParenToken (which will be missing) with your own. I don't know if this is the best way (I'm still a beginner myself), but something like that should work.

    Good luck!

    27 กุมภาพันธ์ 2555 9:08