Roslyn: Access XAML of a partial class from code analyzer - c#

The context: we are currently using a solution where all localizable strings are in XAML files which are translated. For translating strings in code, we use a function that will search from associated resource dictionary:
MessageBox.Show(this.i18n("my message"));
I would like to implement a code analyzer that will check if the "my message" string is actually declared in associated XAML file. The problem is that I can't find anything in compilation context that would lead me to the correct XAML file.
If the resource management is outside of the scope for Roslyn I could use DTE Interface for my task but I would like to know if there are better solutions for it.

Roslyn exposes an AdditionalFiles mechanism where you can specify some additional files to be passed into your analyzer which you need the content of. XAML files for what you're doing would be a perfect example. We have one Roslyn analyzer that we run on Roslyn itself that verifies that the types we have in our API match an additional file (called PublicAPI.Shipped.txt). If you look at this as a sample it'll show you how to read in extra files.
This doesn't give you any help at interpreting the files (you'll need to parse them yourself), but this at least gives you the mechanism to get the contents of them. We'll take care of all the mucking around reading the file from disk and everything for you.
You still have to specify that you actually want the files to be included in the AdditionalFiles list in the first place. If you look here you can see that you can specify an MSBuild item group name that will get passed through everything.

Related

Output a Roslyn MSBuildWorkspace to different folder

When executing
mSBuildWorkspace.TryApplyChanges(solution);
Visual Studio changes the solution in place. This means that if I want to output to a different location, I need to first copy the whole solution to the requested target and only then work on it. This is error prone as the solution might have relative path links to dependencies, which can break when moving the solution.
So is there a way to tell MSBuildWorkspace to output the changes to a different folder than the source?
There's no built-in support for this.
Option #1: Instead of instead of calling TryApplyChanges you could call Solution.GetChanges to figure out what changed compared to what was originally loaded, and then call the various methods to get the changed documents and apply the edit yourself. This means you're on the hook to actually apply the edits -- source file edits are easy (just write the updated text) but if you care about more complicated things like project changes (adding/removing references) you don't really have a way to leverage MSBuildWorkspace's support for those sorts of things.
Option #2: Roslyn's open source, so you'd have to modify MSBuildWorkspace yourself to allow such a redirection, which would let you potentially try to reuse some of the more complicated logic around project manipulation. Or you can just copy/paste the implementation of the applying, and then use Solution.GetChanges and the reused code.

How would I replicate a file hierarchy from template?

I need to restore a certain file hierarchy in a folder, after it gets deleted (yeah, don't ask).
For now I imagine it as a simple application that gets run by Windows Task Scheduler. While there are some ways to achieve that effect, I wanted to create a simple single exe.
So I put my structure into my project, and set all files Build Action to "Embedded resource". I can sort of access them through Assembly.GetExecutingAssembly().GetManifestResourceNames() and Assembly.GetExecutingAssembly().GetManifestResourceStream(name), however I don't see any simple way to preserve hierarchy like that.
While I'm solving a real problem, the question is more academic in nature - I don't need anything convoluted, like parsing resource name to determine what hierarchy it resulted from. My file structure actually is just 4 files in two folders, if push comes to shove I can just write everything out manually.
I'm sure there should be a simple way to just say "Hey, here's how those files should be arranged, repeat". Maybe resources are a wrong mechanism?
You're right, you can't. Because resource names are identifiers, some characters are replaced during the build and you can't store empty folders either You can however build a Zip file from the structure embed that single file and extract it when needed - with one single call if you want. The framework has built-in zip support. Please note however that the ZipFile can't be accessed concurrently only sequentially as there is only a single inner state.

Where or how I can get the full list of C# reserved words/methods/namespaces/... for autocomplete

I'm doing an autocomplete editor for C# language, and need to get all the words/methods/namespaces/proprieties in C#.
Didn't found anything useful in google.
Also tried with reflection but can't get all items like namespaces after System or other namespaces.
Is there a dictionary with all this on internet, or is there a method to do it with reflection?
for exemple:
User is typing System.
The autocomplete found the System as a namespace and showing all the types/methods and namespaces inside it.
or user is typing Bitmap (if I will not find the Bitmap as a root type, then I will try all the combinations of the using XXX.YYY, like XXX.YYY.Bitmap...)
Thanks
P.S. Please don't recommend me MSDN because I already know about it and this will be the last and worst option, to parse recursively all information on MSDN and save it in a database.
As per #Steve Wellens' comment, there is difference between C# and .NET type names. You have two very different problems to deal with:-
Gaining knowledge of C# - will allow your editor to know about C# keywords, etc. This can be found in the C# language spec, as per #Cody Gray's answer. This does not vary according the context of the particular file you are editing (unless you want your editor to have the option to be able to restrict to older version of C# in which case you will need to build in knowledge of previous versions of the spec).
Gaining knowledge of the types available in the current editing context. For this, you need to know which namespaces have been declared in using statements in the current file and which libraries have been referenced by the project containing the current file. There is no point trying to find out all this information globally for every single library available since the amount of information will be too huge and continuously changing. You could, perhaps, build in knowledge of all type names available in the GAC. In the case of a partial typename, e.g. Bitmap, a simple implementation would use the using statements contained in the file to attempt to determine which type name is being referred to by examining the relevant assemblies referenced by the project containing the current file (conflicts can occur and will need user resolution, e.g. prefixing the partial type name with some more elements of the actual namespace). This is how the Visual Studio editor works. A richer implementation can examine all assemblies referenced by the project containing the current file plus all those contained in the GAC and, if required, suggest either addition of the full name space to the type name or the addition of a using statement. This is how Resharper works.
Did you try the MSDN documentation, for both the .NET Framework and the C# language? This is the closest you'll come to a "directory with all this on [the] internet".
You might also peruse the C# language spec.

Need to traverse through .cs files in a solution and determine if a function is used

I am looking to write a utility for work where I can take a list of generated function names (we use a custom-code generation process) and traverse through all of the .cs files within a particular solution and determine if the function is being used. The most difficult thing preventing me from figuring this out is determining whether or not the function is within a commented line or block of code. I planned on just looping through each .cs file and using a streamreader looking for a match on the function name. Is that a good approach to start with?
NOTE: This is a utility that I am looking to write that I can use with various solution files. We have thousands of generated functions from our code-gen utility and I am looking to report on the unused functions.
I would compile the code and use a tool like NDepend on it, no reason to reinvent the wheel.
This process can be very well automated using a CQL (Code Query Language) statement.
I've always gone to:
Edit -> Find and Replace -> Find in Files.
Then a window pops up. You select "Entire Solution" from the 'Look In' drop-down. And then type what you're looking for in the "Find What" field.
EDIT: Oh, I see that you're looking for a list of functions. My apologies. I guess this only works for single items...
The csproj file is xml, so you can use that to get a list of files listed in your projects. You can single out your method names by looking for code outside of braces within a class, then parsing out any modifiers, return types and arguments, then search each file for all the method names found. Bonus for stripping comments out of the file before processing.
I am doing something very similar with C code currently, and its worked out alright.
One thing I've done to find function calls (I have a list of calls where I care if they are called in a file) is as follows:
Run a regex for the function name on a file that has been stripped of all comments
If the regex finds a match, check the file line by line (I report what line a function call was found on)

C# Code Generation

I am looking at creating a small class generator for a project. I have been reading about CodeDOM so it the semantics of creating the classes does not appear to be an issue, but am unsure oh how to best integrate the generation into the development and deployment process.
How should I trigger the creation of the classes? I have read it should be part of the build process, how should I do this?
Where should the classes be created? I read that the files should not be edited by hand, and never checked into source control. Should I even worry about this and just generate the classes into the same directory as the generator engine?
Take a look at T4 templates (it's built in to VS2008). It allows you to create "template" classes that generate code for you. Oleg Sych is an invaluable resource for this.
Link for Oleg's tutorial on code generation.
The answers to your question depend partly on the purpose of your generated classes.
If the classes are generated as a part of the development, they should be generated as text files and checked into your SCM like any other class.
If your classes are generated dynamically at runtime as a part of the operation of your system, I wouldn't use the CodeDOM at all. I'd use Reflection.
I know of the presence of T4 templates (and know many people use them), but I have not used them myself. Aside from those, you have two main options:
Use a SingleFileGenerator to transform the source right inside the project. Whenever you save the document that you edit, it will automatically regenerate the code file. If you use source control, the generated file will be checked in as part of the project. There are a few limitations with this:
You can only generate one output for each input.
Since you can't control the order in which files are generated, and the files are not generated at build time, your output can only effectively be derived from a single input file.
The single file generator must be installed on the developer's machine if they plan to edit the input file. Since the generated code is in source control, if they don't edit the input then they won't need to regenerate the output.
Since the output is generated only when the input is saved, the output shouldn't depend on any state other than the exact contents of the input file (even the system clock).
Generate code as part of the build. For this, you write an MSBuild targets file. For this, you have full control of input(s) and output(s) so dependencies can be handled. System state can be treated as an input dependency when necessary, but be remember that every build that requires code generation takes longer than a build which uses a previouly generated result. The results (generated source files) are generally placed in the obj directory and added to the list of inputs going to csc (the C# compiler). Limitations of this method:
It's more difficult to write a targets file than a SingleFileGenerator.
The build depends on generating the output, regardless of whether the user will be editing the input.
Since the generated code is not part of the project, it's a little more difficult to view the generated code for things like setting breakpoints.

Categories