Help with parsing InitializeComponents

SyntaxEditor .NET Languages Add-on for Windows Forms Forum

Posted 16 years ago by Michel van den Berg
Version: 4.0.0276
Avatar
I am in need of parsing InitializeComponent. In C#, aswell as in VB.Net, this method is in most cases placed in a [filename].designer.[extension] file. However, this might not be the case, as it can be placed within the [filename].[extension] file aswell! Because of this I need SE to parse both files (I can give them both files, that's no problem) and then resolve the type and get the InitializeComponent AST. I've tried two ways:

1. Do a Document.LoadFile([filename].[extension]), and assign the code of the [filename].designer.[extension] to the footertext property of this document. However, do note that there are two classes (with one being partial). I didn't think I could get the needed AST from Document related functions. I've tried using dotNetProjectResolver.SourceProjectContent, but it didn't work out: it does add a sourcekey, but no types are returned for the sourcekey (using GetTypesForSourceKey). Would you recommend me using the ProjectResolver or would you use the Document to get the needed AST?

2. Do a Document.LoadFile([filename].[extension]), and add the code of the [filename].designer.[extension] to the ProjectResolve using LoadCode() or LoadFile(). The same problem exists here: no types are returned for the sourcekey.

Regards,

Michel van den Berg
Microsoft Student Partner, The Netherlands
Website: http://www.promontis.nl

Comments (25)

Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hi Michel,

Right now, partial types for the same type in the same file will not parse correctly. If you have them in two separate files or documents it should work though.

You should be able to load both files like this (this comes from the DotNetReflectionForm.cs):
dotNetProjectResolver.SourceProjectContent.LoadForFile(cSharpLanguage, Program.ProjectPath + @"ColorButton.cs");
Then use the same source key and it should retrieve a merged IDomType containing the info from both files.

If you aren't seeing that then please make a simple sample project showing what I suggested. Thanks!


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
Actually, I never got GetTypesForSourceKey() to work in my app! In your sample, it does work! Am I doing something wrong, because I don't see it. Please have a look at: http://www.promontis.nl/ExampleSolution.rar

Regards,

Michel van den Berg
Microsoft Student Partner, The Netherlands
Website: http://www.promontis.nl
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Please make sure you follow the "key steps for getting started" section in the main .NET add-on documentation. At a quick glance I see that you never set a cache path for the project resolver. That perhaps could be your problem.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
From what I can see, it DOES work when the SE is showing. However, I do a LoadFile(), then I need to get the Types and then I show the SE. So, before the SE is shown I get empty Types (along with no sourcekeys). But after the SE is shown, I get the wanted results! Is this a bug? Or by design?
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Without debugging it, it's hard to say. Setting the Document.Text (via LoadFile) should always initiate parsing regardless of whether the SyntaxEditor is loaded or not since the Document is independent of the SyntaxEditor in regards to parsing.

My guess is that perhaps you didn't do all your project resolver or semantic parser service setup before the first SyntaxEditor is loaded. Or you assign a new project resolver by accident when your SyntaxEditor is loaded, etc.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
I've actually tried in the samples too! In the MainForm sample, at the end of the ctor, I expect dotNetProjectResolver.SourceProjectContent.GetSourceKeys() to return something. It doesn't return anything. When I hook into say a button event, and try to evaluate dotNetProjectResolver.SourceProjectContent.GetSourceKeys() it does work. This is the same issue I am describing in the previous. Can you reproduce this behaviour?
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Oh, it's probably just a timing thing. Remember that a working thread is used to do the semantic parsing (in the service). So it probably hasn't completed yet by the time you make the request.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
Yeah, I've thought about that too. Any suggested steps I should take to be able to wait for it to complete?

Update: I've just added ... SemanticParserService.WaitForParse(SemanticParserServiceRequest.GetParseHashKey(editor.Document, editor.Document), 60000) just before the end of the ctor. It waits a minute, so it should be long enough IMO! Still no good result using dotNetProjectResolver.SourceProjectContent.GetSourceKeys()...


[Modified at 09/30/2008 10:33 AM]

[Modified at 09/30/2008 10:34 AM]
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
There may be an issue with how it is used, where WaitForParse could be blocking the thread from completing. You may have better luck starting a Timer and checking the SemanticParserService.IsBusy property every few seconds. Once that is false, it should be done with everything.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
Ah ok... Perhaps that's the case; the IsBusy property return true even after the WaitForParse! Wouldn't it be nice to have an event in the SemanticParserService (or in the SemanticParserServiceRequest) which raises when the parsing is completed? I don't really like the idea of running a timer each time I load a document...
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Actually, we do have something along those lines already. The SourceProjectContent object (off of DotNetProjectResolver) has a SemanticParseComplete event that fires when a file has been parsed. It passes the SemanticParseServiceRequest along to you too. That's probably what you want.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
Nice! Will try to see if that works... currently I am using a timer and it works!
Posted 16 years ago by Michel van den Berg
Avatar
From what I can see, the dotNetProjectResolver.SourceProjectContent.SemanticParseComplete event is never raised. I've added a handler to this event on the first line of the constructor in the MainForm sample; the handler is never reached. For example, I would expect it to be reached just before showing the form, or when I press "Reparse Document"... am I doing something wrong?

[Modified at 10/03/2008 07:15 PM]
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Oh, sorry. The SourceProjectContent.SemanticParseComplete event only fires if you did a call to SourceProjectContent.LoadForCode or LoadForFile. For changes made in a Document, it won't fire.

However Document has a SemanticParseDataChanged event that fires when a Document is done doing semantic parsing. Likewise, SyntaxEditor.DocumentSemanticParseDataChanged can be used if you'd prefer to attach to the containing SyntaxEditor instead.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
Currently, I am hooking into the events you've posted, and all works like a charm! Though, I have a remark about resolving partial class types. When working with WinForms you'll mostly have a partial class implementing the InitializeComponent method. I am loading both files and you've assured me that you merge them within the SourceProjectContent. I can confirm this. However, I would expect both sourcekeys would return the merged class type: this is not the case! From what I've seen it depends on the order of loading the files. The last loaded file with a specific sourcekey won't return a type using GetTypesForSourceKey.

Update:
It also seems the sourcekey parameter for GetTypesForSourceKey, is case sensitive. Could you provide an overloaded method with a StringComparison parameter?

[Modified at 10/09/2008 03:18 AM]
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Hmm, I'm not seeing that. I loaded our .NET Reflection quickstart and made BaseControl.cs and InheritedControl.cs both partial classes and both be BaseControl. Then in response to one of the toolbar buttons I added this:
ICollection c = dotNetProjectResolver.SourceProjectContent.GetTypesForSourceKey("BaseControl.cs", true);
ICollection c2 = dotNetProjectResolver.SourceProjectContent.GetTypesForSourceKey("InheritedControl.cs", true);
I saw the merged type object in both collections.

The source key is case sensitive and is used internally that way. So I'd recommend that instead you simply use all lowercase filenames when setting Document.Filename or loading/checking other ways.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
If tried what you've suggested and I can confirm it works. However, it's valid to allow at most one partial declaration to omit the partial keyword (this is what the designer file does). When you remove one of the two partial keywords in your suggestion, then only one GetTypesForSourceKey returns a value while the other returns null. Can you confirm this?
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Ahh yes that certainly is the problem here because VS seems to violate the definition of the partial class functionality. This comes right out of the MSDN for partial classes:

Quote:
All the parts must use the partial keyword. All the parts must be available at compile time to form the final type. All the parts must have the same accessibility, such as public, private, and so on.


That says that all the declarations must be marked with partial.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
That's indeed true from the official c# 3.0 language spec. However, same spec for vb.net explicitly says:

Quote:
When combining partial type declarations, at least one of the declarations must have a Partial modifier, otherwise a compile-time error results.


Also:

Quote:
Although it is possible to specify Partial on only one declaration among many partial declarations, it is better form to specify it on all partial declarations. In the situation where one partial declaration is visible but one or more partial declarations are hidden (such as the case of extending tool-generated code), it is acceptable to leave the Partial modifier off of the visible declaration but specify it on the hidden declarations.


It seems VS reflects this: for C# they have the partial keyword on all declarations, but for vb.net they have it only for the designer file.
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
Ok what we'll do is make a change so that VB source files assume partial is always specified while C# remains like it is.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
Great! Do you perhaps have an estimate on when you'll release this?
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
We're trying for this week.


Actipro Software Support

Posted 16 years ago by Michel van den Berg
Avatar
Wow... that's fast! Thanks for the great support!
Posted 16 years ago by Michel van den Berg
Avatar
Just installed the new build and the partial classes issue has been resolved! Great job, and fast too! I do however, have a new problem: GetTypesForSourceKey() used to return a TypeDeclaration, but now it returns the internal class d. I used to use a visitor to walk the AST for the TypeDeclaration, but since d can't be casted to TypeDeclaration (only to IDomType) that doesn't work anymore. Is there any way to convert the IDomType to TypeDeclaration (or a type supporting the visitor)?
Posted 16 years ago by Actipro Software Support - Cleveland, OH, USA
Avatar
The internal class 'd' is an IDomType that doesn't implement IAstNode (since it isn't an AST node). Rather it is a type the merges together one or more other IDomTypes.

So unfortunately you can't use the AST visitor on that class. You'll have to just use the various properties and methods of IDomType to get at its data, similar to how you would for a type defined in an assembly.


Actipro Software Support

The latest build of this product (v24.1.0) was released 2 months ago, which was after the last post in this thread.

Add Comment

Please log in to a validated account to post comments.