Custom naming rules in ReSharper - c#

The project I'm working on (C# on VS 2015 with ReSharper 2016.1.2) has a new requirement which requires us to remove all usages of p_ prefixes in parameter names (p_Param becomes param).
I'd like to create a ReSharper Code Inspection Custom Pattern to take care of this for me (to match the string pattern with squiggly lines and auto-fix in the solution).
I've followed the tutorial at https://www.jetbrains.com/help/resharper/2016.1/Code_Inspection__Creating_Custom_Inspections_and_QuickFixes.html but I'm a bit stuck.
I've tried the following patterns:
Var 1
Find: $prefix$$varName$ ($prefix$ - identifier, matching regex [^p_*] (start with p_, continue with anything, $varName$ - identifier)
Replace $varName$
Var 2
Find: p_$varName$ ($varName$ - identifier)
Replace $varName
I'd also need to transform the $varName$ identifier from PascalCase to cammelCase (no ideea how to do this).
When searching via 'Search now' - no results are found in either situation.
Any help is appreciated.

Using ReSharper, you can change the naming style of variables and have it apply to an entire solution.
The location of this option will (probably) vary but for my version of R# (2016.1.2), it's under ReSharper->Options->Code Editing->C#->Naming Style:
From there, change the Entity Kinds to how you want them to appear. In mine, I prefer _lowerCamelCase for private instance fields for example.
Once your changes are made, find any field of that type in code (I'll use a private variable) that doesn't follow that format, click it and then click the light bulb to the left. From there mouse-over the arrow on "Rename to ......" and select Fix naming in solution.
You might have to do it a few times but that's how I rename stuff based on my preferred code style.

Related

Moving away from primary constructors

The C# 6 preview for Visual Studio 2013 supported a primary constructors feature that the team has decided will not make it into the final release. Unfortunately, my team implemented over 200 classes using primary constructors.
We're now looking for the most straightforward path to migrate our source. Since this is a one time thing, a magical regex replacement string or hacky parser would work.
Before I spend a lot of time writing such a beast, is there anyone out there that's already done this or knows of a better way?
As I suggested in comments, you could use the version of Roslyn which does know about primary constructors to parse the code into a syntax tree, then modify that syntax tree to use a "normal" constructor instead. You'd need to put all the initializers that use primary constructor parameters into the new constructor too, mind you.
I suspect that writing that code would take me at least two or three hours, quite possibly more - whereas I could do the job manually for really quite a lot of classes in the same amount of time. Automation's great, but sometimes the quickest solution really is to do things by hand... even 200 classes may well be faster to do manually, and you could definitely parallelize the work across multiple people.
(\{\s*)(\w*\s*?=\s*?\w*\s*?;\s*?)*?(public\s*\w*\s*)(\w*)(\s*?{\s*?get;\s*?\})(\s*?=\s*?\w*;\s*)
\1\2\4\5
A few answers: the first with a simple Regex find and replace which you need to repeat a few times:
Regex: A few lines of explanation then the actual regex string and replacement string:
a. In regex, first you match the full string of what your looking for (in your case a primary constructor). Not hard to do: search for curly bracket, the word public, then two words and an equals sign etc. Each text found according to this is called a Match.
b. Sometimes there are possible repeated sequences in the text that you are looking for. (In your case: The parameters are defined in a line for each). For that, you simply mark the expected sequence as a Group by surrounding it with parenthesis.
c. You then want to mark different parts of what you found, so you can use them or replace them in your corrected text. These parts are also called "Groups" actually "Capture Groups". Again simply surround the parts with parenthesis.
In your case you'll be retaining the first captured group (the curly bracket) and the name of the property with its assignment to the parameter.
d. Here's the regex:
(\{\s*)(\w*\s*?=\s*?\w*\s*?;\s*?)*?(public\s*\w*\s*)(\w*)(\s*?{\s*?get;\s*?})(\s*?=\s*?\w*;\s*)
1. (
// ---- Capture1 -----
{
// code: \{\s*?
// explained: curley bracket followed by possible whitespace
)
2. ( - Capture2 - previously corrected text
// - possible multiple lines of 'corrected' non-primary-constructors
// created during the find-replace process previously,
Propname = paramname; // word, equals-sign, word, semicolon
// code: \w*\s*?=\s*?\w*\s*?;\s*?
// explained: \w - any alphanumeric, \s - any whitespace
// * - one or more times, *? - 0 or more times
)*?
// code: )*?
// explained: this group can be repeated zero or more times
// in other words it may not be found at all.
// These text lines are created during the recursive replacement process...
3. (
// ----Capture 3-----
// The first line of a primary constructor:
public type
// code: public\s*\w*\s*
// explained: the word 'public' and then another word (and [whitespace])
)
4. (
// ----- capture 4 -----
Propname
// code: \w#
// explained: any amount of alphanumeric letters
)
5. (
// ---- capture 5 ----
{ get; }
// code: \s*?{\s*?get;\s*?\}
)
6. (
// ---- capture 6 ----
= propname;
code: \s*?=\s*?\w*;\s*
explained: by now you should get it.
The replacement string is
\1\2\4\6
This leaves:
{
[old corrected code]
[new corrected line]
possible remaining lines to be corrected.
Notepad++ 10 minutes trial-and-error. I guarantee it won't take you more than that.
Visual Studio 2014 refactor. but
a. You have to install it on a separate VM or PC. MS warns you not to install it side by side with your existing code.
b. I'm not sure the refactor works the other way. [Here's an article about it][1]
Visual Studio macros. I know I know, they're long gone, but there are at least two plugins that replace them and perhaps more. I read about them on this SO (StackOverflow) discussion. (They give a few other options) Here:
Visual Commander - Free open source Visual Studio macro runner add-on
VSScript - A Visual Studio add-on: costs $50 !!
Try Automatic Regexp by example:You give it several examples of code in which you highlight what IS the expected result, and then the same (or other) code in which you highlight what IS NOT the expected result. You then wait for it to run through the examples and give you some regex code.
// for the following code (from http://odetocode.com/blogs/scott/archive/2014/08/14/c-6-0-features-part-ii-primary-constructors.aspx )
public struct Money(string currency, decimal amount)
{
public string Currency { get; } = currency;
public decimal Amount { get; } = amount;
}
// I get something like: { ++\w\w[^r-u][^_]++|[^{]++(?={ \w++ =)
Play with the regexp on this great site: https://www.regex101.com/
// I first tried: \{\s*((public\s*\w*\s*)\w*(\s*?{\s*?get;\s*?})\s*?=\s*?\w*;\s*)*\}
The repeated sequence of the primary-constructor lines (the "repeated capture group") only captures the last one.
Use c# code with regex.captures as explained here in another StackOverflow (see accepted answer)

Automated refactoring: Add an argument to all method invocations

So, in my ASP.NET C# code base I have possibly hundreds of bits of code like this:
Response.Redirect("something.aspx?Error=" + ex.Message);
I want to automatically add an argument to all of these method calls to add 'true' as the second parameter to this method, like this:
Response.Redirect("sometihng.aspx?Error=" + ex.Message, true);
I have Visual Studio 2010 and the latest version of Resharper at my disposal.
I tried using the 'Search with Pattern' feature in Resharper (VS menu -> ReSharper -> Find -> Search with Pattern) to see if this would automatically refactor my codebase, but I'm not sure exactly how or if it works. Here's what I tried:
On the right-hand side, I created an 'Argument' placeholder called 'anyString', in the hope that this would find and replace all invocations of Response.Redirect that have a string in the first argument, but this found no matches in my code-base.
Any ideas on how I might solve this without resorting to manually changing all references?
As per the Jetbrains Resharper documentation on 'Searching a Code with Pattern':
Pay attention, that when you use a placeholder, its name should be
enclosed with dollar signs (use the syntax $xx$, where xx represents
placeholder name),whereas when you create a new placeholder, you
should omit these special symbols.
Therefore, I was on the right track. Also for the placeholder I just need '$anyString$' and it will find all invocations of the method, even if they are made up multiple string objects (e.g. string literals and string objects). So this is how it would look:
The 'anyString' placeholder pattern was created by performing the following steps:
1) Click 'Add Placeholder' -> Argument
2) Give it a name, e.g. 'anyString'
For my case, I also checked the 'Limit minimal number of arguments' and selected 1, and I also checked the 'Maximal' box and set that to 1 also.
The 'Save' button is also useful if you intend on reusing the pattern again.

How do I make FxCop understand a 'multi-case' word?

I work in a company that their acronym is something like XyZ (uppercase followed by lowercase than followed by uppercase again).
This word is spread across all our namespaces. When I run FxCop against our projects it accuses IdentifiersShouldBeCasedCorrectly (CA1709). The suggestion is to capitalize just the first letter (what I don't want).
How do I make FxCop understand that the word XyZ is known, spelled correctly and properly cased? (In other words, that is well-written).
I added the word to the CustomDictionary.xml file: I've added to Recognized words; Unrecognized words; and alsoAcronyms with CasingExceptions. None of these made any effect.
I also verified that FxCop is indeed reading the custom dictionary file, when I add another word in the acronym it stops reporting as a casing error as expected (but only for all caps words).
I'm using FxCop 1.36 (the GUI one) with C# projects.
Update
Adding just Xy to casing exceptions seems to make FxCop ignore XyZ as I want.
Still not a great solution since it will allow wrong words like XyX or XyW when the (only) correct one is XyZ.
You can add XyZ to an FxCop dictionary - see How to: Customize the Code Analysis Dictionary.
Code Analysis uses a built-in dictionary to check identifiers in your code for
errors in spelling, grammatical case, and other naming conventions of the .NET
Framework guidelines. You can create a custom dictionary Xml file to add,
remove, or modify terms, abbreviations, and acronyms to the built-in dictionary.
Dictionary/Acronyms/CasingExceptions/Acronym
<Dictionary>
<Acronyms>
<CasingExceptions>
<Acronym>NESW</Acronym> <!-- North East South West -->
...
</CasingExceptions>
...
</Acronyms>
...
</Dictionary>
Terms in the Dictionary/Acronyms/CasingExceptions node are applied to the following code analysis rules:
CA1709: Identifiers should be cased correctly

Dictionary<string,List<service>> not allowed in staruml

I am using whitestaruml 5.4
with class diagram, i can't seem to be able to type this attribute
ServiceCategory: Dictionary<string,List<service>>
But Dictionary<string,List<service>> is a valid type for C#, how to get over this?
I suppose you are getting a lexical error on '<' as currently the input analyzer in WhiteStarUML does not accept embedded delimiters ( <[( style ) in the entity names to better handle matching opening/closing at lexer level. In the future this may get more sophisticated but currently the best way to skip parsing is to select the attribute in Model Explorer and fill the "Type" field in Property Inspector. As no parsing happens there it will be accepted. Just make sure not to modify the attribute in the Model View on the Diagram again.
It's June 2022 - still not fixed. Very disappointing.
When directly entering attributes, I just put a placeholder type (e.g., 'foo'). After which, you can go click on the attribute on the right pane and go down to the Editors / type field and replace it with what you want.
I use a lot of map<string,string> and have to do this often. If you try to directly edit a method and its arguments later, it will block you again and you'll have to repeat the procedure - but it can be done to make your diagrams correct. It's just a PITA.

How to fix violation of StyleCop SA1305 (Hungarian)

My code contains a variable named "m_d3dDevice".
StyleCop complains about this name:
SA1305: The variable name
'm_d3dDevice' begins with a prefix
that looks like Hungarian notation.
Remove the prefix or add it to the
list of allowed prefixes.
(Note I have manually disabled SA1308 ("m_"), one of the few rules I'm willing to disobey.)
I can't allow "d3d" as an exception in the Hungarian tab, as it only allows 1 or 2 char prefixes, and allowing "d3" didn't help. I've tried everything I can think of to add "d3d" to my CustomDictionary file (and anyway the docs imply the CustomDict isn't used for rule 1305).
Any suggestions to make StyleCop allow this one? It is a matter of pride now to not have to F2 my variable.
You can also suppress stylecop on a case-by-case basis. e.g.
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Microsoft.StyleCop.CSharp.NamingRules",
"SA1305:FieldNamesMustNotUseHungarianNotation",
Justification = "Using Win32 naming for consistency.")]
IntPtr hFile;
This might not be an attractive option if you have numerous offending names, but for one or two, it's generally fine.
You can also use the Settings.StyleCop in the package files to configure the settings.
You can suppress specific words by adding below code to the Settings.StyleCop file:
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<AnalyzerSettings>
<CollectionProperty Name="Hungarian">
<Value>as</Value>
<Value>do</Value>
<Value>id</Value>
<Value>if</Value>
<Value>in</Value>
<Value>ip</Value>
<Value>is</Value>
<Value>mx</Value>
<Value>my</Value>
<Value>no</Value>
<Value>on</Value>
<Value>to</Value>
<Value>ui</Value>
<Value>vs</Value>
<Value>x</Value>
<Value>y</Value>
<Value>z</Value>
<Value>iOS</Value>
<Value>IOS</Value>
</CollectionProperty>
</AnalyzerSettings>
</Analyzer>
You can suppress the Hungarain Rule itself by adding the following to the Settings.StyleCop file
<Analyzer AnalyzerId="StyleCop.CSharp.NamingRules">
<Rules>
<Rule Name="FieldNamesMustNotUseHungarianNotation">
<RuleSettings>
<BooleanProperty Name="Enabled">
False
</BooleanProperty>
</RuleSettings>
</Rule>
</Rules>
</Analyzer>
You could take a look at StyleCop+.
It contains flexible naming rules that will allow you to force all private fields be named starting with "m_" (or whatever you wish) instead of disabling name checking (like you did).
Regarding "d3dDevice" - it's a very interesting case. Logically, it splits to the following words - { "d", "3", "d", "Device" } or { "d3", "d", "Device" }. And the second "d" seems not to follow "camelNotation".
But, I strongly believe that static analysis (particularly naming) should be flexible enough to satisfy user needs. Currently StyleCop+ can support your case in the following way - for example, you can add "exception" (as many as you want) to naming template for private fields, so that it will look like:
m_$(aaBb)
m_d3d$(AaBb)
This is more likely to be workaround, but I will think about your "d3d" case - and maybe StyleCop+ will support something like this.
Thank you for the interesting example!
Adding suppression attribute should be done on top of all methods which will take time and a long process.
If you would like to remove this rule from your project try this
Right click on your project
Select Stylecop Settings
Find SA1305
Uncheck the rule from result set
Click Apply - OK
Rerun style cop rules again.

Categories