Parsing C# code for contextually aware semantic highlighting - c#

I'm working on a semantic highlighting plugin for VS. Here you can see a web Example.
The goal:
Acquiring all variables and creating different Classifications for every one of them.
The problem:
Getting the variables from the code without writing a C# lexer.
My current approach uses an ITagger. I use an ITagAggregator to get the tags of all the spans that get passed to the ITagger. Then I filter those and get only spans with the "identifier" classification which includes varibles, methods names, class names, usings and properties.
public class Classifier : ITagger<ClassificationTag> {
public IEnumerable<ITagSpan<ClassificationTag>> GetTags(NormalizedSnapshotSpanCollection spans) {
ITextSnapshot snapshot = spans[0].Snapshot;
var tags = _aggregator.GetTags(spans).Where((span) => span.Tag.ClassificationType.Classification.Equals("identifier")).ToArray();
foreach(var classifiedSpan in tags) {
foreach(SnapshotSpan span in classifiedSpan.Span.GetSpans(snapshot)) {
//generate classification based on variable name
yield return new TagSpan<ClassificationTag>(span, new ClassificationTag(_classification));
}
}
}
}
It would be a lot easier to use the builtin C# Lexer to get a list of all variables bundled to a bunch of meta data. Is this data available for plugin development? Is there an alternative way I could acquire it, if not?

The problem: Getting the variables from the code without writing a C# lexer.
Roslyn can do this: https://roslyn.codeplex.com/
There's even a Syntax Visualizer sample that might interest you. I also found an example using Roslyn to create a Syntax Highlighter.

Visual Studio exposes that information as a code model.
Here is an example how you can access class, and then find attribute on the class, and parse attribute arguments:
Accessing attribute info from DTE
Here is more information about code models:
http://msdn.microsoft.com/en-us/library/ms228763.aspx
Here's also automation object model chart what I've been using quite few times: http://msdn.microsoft.com/en-us/library/za2b25t3.aspx
Also, as said, Roslyn is indeed also a possible option. Here is an example for VS2015 using roslyn: https://github.com/tomasr/roslyn-colorizer/blob/master/RoslynColorizer/RoslynColorizer.cs

For building language tools if may be better to use a parser generator for C#. The GOLD parsing system is one such toolkit which can handle LALR grammars. It has a .NET component based engine that you can use in your project and it can be used to integrate with any IDE. You can also find the grammars for various programming languages including C#.

Related

How to add completion words dynamically to VS2013 Syntax Extension (MEF)

It's very possible that I just don't understand the problem space, but I'm having trouble figuring out the MEF (Editor Classifier project).
I've created (piecing together the Walkthrough guides from MSDN https://msdn.microsoft.com/en-us/library/ee197665.aspx) a syntax highligher for Informix Stored Procedure language.
One major problem I have is - I want to be able to find all instances of the keyword "DEFINE" and populate the word directly following it into the Statement Completion extension I have (currently it's populated from a defined list of words).
Much like C#'s native support - when you define a variable, it becomes available in the autocompletion dropdown.
I got rid of the in class hardcoding (from the walkthrough) and my completion words are defined like this:
List<Completion> completions = new List<Completion>();
CompletionTags completionTags = new CompletionTags();
foreach (string completionTag in completionTags.completionTags)
{
completions.Add(new Completion(completionTag));
};
My CompletionTags class is pretty simple:
class CompletionTags
{
public List completionTags;
public CompletionTags()
{
this.completionTags = new List<string> {
// SQL keywords
"COUNT",
"FROM",
"HAVING",
};
}
I know WHAT I need to do. I somehow need to hijack the buffer when it changes and find all occurrences of 'DEFINE ([a-zA-Z0-9_]{1,})' and add \1 to the completionTags list.
I have no idea HOW to do this. Any pointers in the right (or any) direction at this point would be greatly appreciated.
Be kind - we've all been out of our depth at some stage (I've been programming in C# now for 3 days)...
Reading this answer will be helpful.
Look at:
XML Editor IntelliSense Features
Schema Cache

How do I make my own method similar to String.Format using Composite Formatting in C#

I like how String.Format uses arguments to inject variables in to the string it is formatting. This is called Composite Formating and is discussed by MSDN here.
I want this functionality with my logging facade:
string foo = "fancy";
string bar = "message";
log.Debug("My {0} log {1}.", foo, bar)
My ILoggerFacade has the following method signature:
void Debug<T>(T message, params Object[] args);
And, I know I can implement this quite simply:
ILog m_Log = \\some logging implementation
public void Debug<T>(T message, params Object[] args)
{
m_Log.Debug(String.Format(message, args));
}
However, in Visual Studio I don't get the fancy highlighting of the {0}, {1}, ... arguments:
I guess it is ReSharper who is resposible for them, and it seems like it is just ignoring the formatting arguments and giving no "intellisense" help. This isn't good since the other developers who will be using the facade will be expecting this.
How do I get argument highlighting and "intellisense" for custom formatted methods similar to how these work:
Console.WriteLine(...)
String.Format(...)
etc...
Any help would be appreciated.
Check out ReSharpers External Annotations. Specifically, you want to use StringFormatMethodAttribute for this.
To use the External Annotations there are actually 3 methods. Two that it spells out, and one that you have to read between the lines to see.
Reference "JetBrains.Annotations.dll". I would recommend against this one. I don't like the idea of copying the DLL, or having to reference the ReSharper install directory. This could cause issues if you upgrade or re-install.
Copying and pasting attribute declarations into your solution. I'd recommend this as it gives you more control. Additionally, you can get rid of ReSharper (why would anyone do this? Stranger things have happened, I guess.), and still provide this feature to anyone that consumes your library. There are step by step instructions on how to do this in the first link.
Create an XML file, similar to what it uses for for the .NET Assemblies. I did this for the Silverlight Unit Test Framework. ReSharper does not recognize these tests by default.
To do this
Create a file name <assembly>.xml and put it in "ReSharper\vXX\Bin\ExternalAnnotations".
Add a root element "<assembly name="<assembly>">
Now add <member> elements for each member that you want to give an attribute.
I do not recommend doing this for your own code. However, if you have an assembly that you want to have this functionality, but cannot edit, this is the way to do it. This will only apply on your machine and each developer that uses the assembly will need to copy the xml file.

DRY in C# code documentation on two interface variants

I am currently rewriting a SDK to access a webservice.
Since the model for a database query consists of many classes (actually one class for each of about twenty possible filters), I decided to provide a fluent interface additonally.
So instead of
new Query(
Age = new AgeFilter() { From = 18, To = 65 },
Location = new PostalCodeFilter() { Zip = 12345, new RadiusDefinition() { ... } }
);
the user can now write:
Query.Create()
.WithAge(18, 65)
.WithLocation(12345, 50, "miles");
Now I found out that the traditional way has to be included as well (I cannot hide the actual objects as internal).
How can I avoid having to document both the parameters of the fluent interface and the fields of the data classes? The descriptions are the same. I thought about see/seealso but this wouldn't show up in Visual Studio's Code Assistant.
If you use Sandcastle you can use the <inheritdoc /> tag just like this:
///<param name="from">
///<inheritdoc cref="AgeFilter.From" select="/summary/node()" />
///</param>
or
///<summary>
///<inheritdoc cref="QueryFilters.WithAge" select="/param[#name='from']/node()"/>
///</summary>
I don't think you can. An xml-doc comment is applied to a very specific thing and isn't easily "shared". But, you can "link" between elements using the <see> tag. Have a look at http://msdn.microsoft.com/en-us/library/acd0tfbe.aspx and see if it's of use to you.
Understand that DRY really applies mainly to code; writing the same line of code twice means that if a change to the logic inherent in that code has to be made, it has to be made twice. What you're trying to avoid repeating is markup, which while it can have the same inherent problem of having to make changes in multiple places, markup usually has fewer tools available to avoid restating similar things. If you look at other libraries which have multiple ways to accomplish a similar goal, you'll find that a lot of the documentation appears copy-pasted.

what will be the Regular Expression to get all the property and variables names of a class in c#?

What will be the Regular Expression to get all the property and variables names of any class in c#, I want to parse the *.cs file. that is i want to select any *.cs file as input and it should get the property name of that selected class, as an output.
can any one help!!!....would appreciate for any help i tried very much but not got the actual result every time class name is coming instead of property.
thanks
Jack
There's no way you're going to be able to get exactly what you want with a regular expression because you need semantic context, not just string parsing.
For example, a good first attempt at finding all of the field and property definitions in a C# file might go something like this
^\s*(?:(?:private|public|protected|internal)\s+)?(?:static\s+)?(?:readonly\s+)?(\w+)\s+(\w+)\s*[^(]
That will match properties (public int Foo {...}) and fields (private int foo;) but not methods (protected void Bar()).
The problem is that a regex engine has no concept of the context within which those tokens appear. It will match both foo and bar in this code:
int foo;
void Stuff()
{
int bar;
}
If you happen to know that your code file follows some coding standards, you may have more luck. For example, if you enforce a style rule that all class members must have access specifiers, then you can make the private/public/etc part of that regex non-optional; since those are only permitted at the class level, it will filter out local variables.
There are other options, none of them too attractive at first glance. There is persistent talk from the C# dev team about exposing the C# compiler as a service in some future version of .NET, which would be perfect here, but I wouldn't expect that any time soon. You could purchase a third-party C# parser/analyzer like this one (caveat: I have zero experience with that, it's just the first Google hit). You could try compiling the .cs file using csc and examining the IL, but you'd need to know all of the third-party references.

C# code generation

i'm about to make a graduation project application
this application is gonna some way receive a description for a situation , and then accordingly generate c# code
i want to know in what field i need to search or how to autogenerate C# code
Have a look at Kathleen Dollard's book on this if you can. She has a website for this topic as well.
You have three options essentially:
Brute-force - creating the code files yourself in a text file
CodeDOM generation - MS's built in way of creating code.
XSLT - What Kathleen uses.
T4 templates can help too -
http://www.hanselman.com/blog/T4TextTemplateTransformationToolkitCodeGenerationBestKeptVisualStudioSecret.aspx
And you could also generate IL on the fly. ;)
CodeDOM
I've done a wrapper around codedom. You only need to create your own C# script and specify the types being used.
Example
public interface IWorld
{
string Hello(string value);
}
string code = #"namespace MyNamespace
{
class Temp : IWorld
{
public string Hello(string value)
{
return "World " + value;
}
}
}";
Compiler compiler = new Compiler();
compiler.AddType(typeof(string));
compiler.Compile(code);
var obj = compiler.CreateInstance<IWorld>();
string result = obj.Hello("World!");
Note that it was a long time ago that I wrote it. The example might not work 100%. (The Compiler class do work, the example might use it incorrectly).
Compiler source code: http://fadd.codeplex.com/SourceControl/changeset/view/65227#925984
Reflection.Emit
You can also generate IL using Reflection.Emit: http://msdn.microsoft.com/en-us/library/3y322t50.aspx
It's a bit harder but more flexible, since CodeDOM generates a new Assembly each type you compile code.
There is a set of MatLab tools that generates C/C++ code from state-charts and data-flow diagrams:
Real Time Workshop
Real-Time Workshop Embedded Coder
Stateflow Coder
You should dig into it.
What will be the "description of a solution" in your case?

Categories

Resources