Getting started

Hi,

I'm writing my new R# plugin, and I've got a couple of questions. I've got a skeleton class inheriting from BulbItemImpl and implementing IContextAction, and then I'm stuck. So, how to:

  • get the list of public properties in the current class?
  • check if a particular class exists?
  • create a particular class?
  • show a standard R# form for a new class, like when you see with "Extract Superclass..", with a list of members?
  • add a property for a particular class?


Thanks a lot!

ulu

7 comments
Comment actions Permalink

Per Twitter, let me see if I put can put together some demos.

0
Comment actions Permalink

>    * get the list of public properties in the current class?

If you get the IClass instance (or any ITypeElement), you can get it's propeties by invoking ".GetProperties()" method, or just calling ".GetMembers()" method and filter it by properties (member is IProperty).
To check wether specific member is public, you can do: member.GetAccessRights() == AccessRights.PUBLIC

>    * check if a particular class exists?

by it's CLR name?

>    * create a particular class?

In which language and in which file? existing or a new one?

>    * show a standard R# form for a new class, like when you see with "Extract Superclass..", with a list of members?
>    * add a property for a particular class?

Get the IClassDeclaration for your class, and invoke ".AddMember(...)" method. To create new property declaration which should be passed tp "AddMember" method, use CSharpElementFactory.GetInstance(module).CreateTypeMemberDeclaration("public in MyProperty {get{......}}");

0
Comment actions Permalink

Thanks a lot, now I'm starting to see the light!

However, several things remain unclear:

pasynkov wrote:

>    * get the list of public properties in the current class?

If you get the IClass instance (or any ITypeElement), you can get it's propeties by invoking ".GetProperties()" method, or just calling ".GetMembers()" method and filter it by properties (member is IProperty).

Given that I have an ICSharpContextActionDataProvider instance and an ISolution instance, how do I get a reference to an IClass(I'm following the instructions found here: http://hadihariri.com/blogengine/post/2010/01/12/Writing-plug-ins-for-ReSharper-Part-1-of-Undefined.aspx

>    * create a particular class?

In which language and in which file? existing or a new one?


My idea was to display an instance of JetBrains.ReSharper.Refactorings.WorkflowW.RefactoringWizardForm, collect information about whether a new file should be created, the name of the new class etc, and then either create a new file or use an existing one.

As for the language, I'm interested in both VB.Net and C# versions, since I program in both languages. Can I make a single CA for both?

>    * add a property for a particular class?


Get the IClassDeclaration for your class, and invoke ".AddMember(...)" method. To create new property declaration which should be passed tp "AddMember" method, use CSharpElementFactory.GetInstance(module).CreateTypeMemberDeclaration("public in MyProperty {get{......}}");


Again, how do I get a reference to an IClassDeclaration instance?

Thanks a lot!!
ulu

0
Comment actions Permalink

1) To get type by it's CLR name use the following:

var cache = PsiManager.GetInstance(solution).GetDeclarationsCache(DeclarationsScopeFactory.SolutionScope(GetManager().Solution, true), true);
var typeElement = cache.GetTypeElementByCLRName(clrName)

3) Adding members to class is language-specific. For example, for C# language you can use the following:

var classDeclaration = typeElement.GetDeclarations().OfType().FirstOrDefault();
var newMethod = CSharpElementFactory.GetInstance(classDeclaration.GetPsiModule()).CreateTypeMemberDeclaration("void Foo() {}");
classDeclaration.AddMember(newMethod);

0
Comment actions Permalink

Thanks, it was really helpful!

(Although the forum ate your angle brackets, as usual, so I had to figure out that typeElement.GetDeclarations().OfType() actually probably means typeElement.GetDeclarations().OfType[JetBrains.ReSharper.Psi.ExtensionsAPI.Tree.CompositeElement]() -- correct me if I'm wrong) (I actually learned it the hard way)

(And it also seems like it doesn't have a definition for AddMember -- you should use "AddChild" -- or not?)

(I'm using R# 5.0)

The last thing that keeps me from building it is that for some strange reason there are several classes in JetBrains.Platform.ReSharper.Util with names like System.Linq.Expressions.Expression and such, so I can't compile my code because of the ambiguous class names. I removed a reference to System.Core, but still cannot compile. The offending line is:
typeElement.GetDeclarations().OfType<CompositeElement>()
and the error is:
The call is ambiguous between the following methods or properties:
'System.Linq.Enumerable.FirstOrDefault<JetBrains.ReSharper.Psi.ExtensionsAPI.Tree.CompositeElement>(System.Collections.Generic.IEnumerable<JetBrains.ReSharper.Psi.ExtensionsAPI.Tree.CompositeElement>)' and 'System.Linq.Enumerable.FirstOrDefault<JetBrains.ReSharper.Psi.ExtensionsAPI.Tree.CompositeElement>(System.Collections.Generic.IEnumerable<JetBrains.ReSharper.Psi.ExtensionsAPI.Tree.CompositeElement>)'

Please help!

ulu

update: I was able to compile it targeting the 3.0 framework. But still can't use AddMember, or AddChild.

0
Comment actions Permalink

Nope.  CompositeElement, AddChild and so on - are *RAW* methods to deal with AST tree. They shouldn't be used directly since it is very easy to make inconsistent tree.  I've meant  typeElement.GetDeclarations().OfType[JetBrains.ReSharper.Psi.CSharp.Tree.IClassDeclaration]().   As for ambiguity - the problem is that ReSharper targets .NET 2.0, so we had to re-implement System.Linq methods by our own to use C# 3 in ReSharper development. To fix it, just exclude System.Linq assembly reference from your plugin

0
Comment actions Permalink

Thanks a lot again, this has been very clear.

ulu

0

Please sign in to leave a comment.