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

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

Related

Custom naming rules in ReSharper

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.

What are some good non-English phrases with singular and plural forms that can be used to test an internationalization and localization library?

I've been working on a .NET library to assist with internationalization of an application. It's written in C#, called SmartFormat, and is open-source on GitHub.
It contains Grammatical Number rules for multiple languages that determine the correct singular/plural form based on the template and locale. The rules were obtained from Unicode Language Plural Rules.
When translating a phrase that has words that depend on a quantity (such as nouns, verbs, and adjectives), you specify the multiple forms and the formatter chooses the correct form based on these rules.
An example in English: (notice the syntax is nearly identical to String.Format)
var message = "There {0:is:are} {0} {0:item:items} remaining.";
var output = Smart.Format(culture, message, items.Count);
I would like to write unit tests for many of the supported languages. However, I only speak English and Spanish (which both have the same grammatical-number rules).
What are some good non-English test phrases that can be used for these unit tests?
I am looking for phrases similar to "There {0:is:are} {0} {0:item:items} remaining.". Notice how this example requires a specific verb and noun based on the quantity.
A note about syntax:
This library looks for : delimited words and chooses the correct word based on the rules defined for the locale. For example, in Polish, there are 3 plural forms for the word "File" : 1 "plik", 2-4 "pliki", 5-21 "plików". So, you would specify all 3 forms in the format string: "{0} {0:plik:pliki:plików}".
The words are typically ordered from smallest possible value to largest, such as "{0:zero:one:two:few:many:other}", as defined by the Unicode Language Plural Rules.
Additional information about this code has been discussed here: Localization of singular/plural words - what are the different language rules for grammatical numbers?
I'd like to contribute with the approximate Turkish translation of your sample phrase, so you can test for the case where number of possible forms equals 1. ;)
{0} nesne kaldı. = ({0} items remaining.)
Although Turkish words are pluralized regularly with suffixes, the plural forms are never used when the number of items are specified. So the above should be rendered the same in each case:
1 nesne kaldı.
2 nesne kaldı.
42 nesne kaldı.
However, when the count is not explicitly specified, it may become grammatically important to indicate if we are talking about one or more items. So the message "Do you want to delete the selected item(s)?" should be rendered like this:
Seçili nesneyi silmek istiyor musunuz? (when item count=1)
Seçili nesneleri silmek istiyor musunuz? (when item count>1)
So I guess the format for this would be:
Seçili {0:nesneyi:nesneleri} silmek istiyor musunuz?

StyleCop/FxCop 10 - How do you properly suppress a message only on a namespace level?

FxCop 10 is complaining about the following:
using XYZ.Blah; //CA1709 - "XYZ"
using Xyz.Blah; //No complaint.
using XylophoneSuperDuperLongFullName.Blah; //I don't want to have a long full name for my company name.
The problem is... I want my company name to show up in all UPPERCASE because XYZ is an abbreviation. The long version of the name is much too long to be a useful namespace. Microsoft gets away with this kind of stuff because their acronym is only 2 letters.
using MS.Something; //No Complaint.
using Microsoft.SomethingElse; //No Complaint.
So, I was looking at adding a SuppressMessageAttribute to suppress this warning. But, I'm not sure how to do so properly to only (or where to even stick it) so that it ONLY affects this one instance. I don't want to Suppress anything within that namespace because I want to catch any other mistakes I make. I did look at at the msdn and google searched but I can't find anything that shows how to specifically just target this instance. The closest I found was Scope = "namespace" but I wasn't sure if that means it affects the actual namespace name or if it affects everything WITHIN that namespace.
MSDN - CA1709: Identifiers should be cased correctly:
It is safe to suppress this warning if
you have your own naming conventions,
or if the identifier represents a
proper name, for example, the name of
a company or a technology.
You can also add specific terms,
abbreviations, and acronyms that to a
code analysis custom dictionary. Terms
specified in the custom dictionary
will not cause violations of this
rule. For more information, see How
to: Customize the Code Analysis
Dictionary.
That being said, if you feel justified to suppress the message, it really isn't hard at all. In FxCop 10 right click on any message you want to suppress and go to Copy As>Suppress-Message or Copy As>Module-level Suppress Message.
You should place the SuppressMessageAttributes in the appropriate locations. Attributes that suppress a single location should be placed on that location, for example, above a method, field, property, or class.
In you're instance, there is no specific location to place the attribute (by default it should copy over as [module: SuppressMessage(...)]. This is a good indication that it belongs either at the top of a file if it is a module-level suppression particular to a file (for example, to a resource specific to a file). Or, and more likely, it belongs in a GlobalSuppressions.cs file.
using System.Diagnostics.CodeAnalysis;
[module: SuppressMessage("Microsoft.Naming", "CA1709:IdentifiersShouldBeCasedCorrectly", Justification = "Because I said so!", MessageId = "XYZ", Scope = "namespace", Target = "XYZ.Blah")]
You can also shorten the CheckId property if you want to, but it's good to know what CA1709 means. If you don't feel like it, this also works:
using System.Diagnostics.CodeAnalysis;
[module: SuppressMessage("Microsoft.Naming", "CA1709", Justification = "Because I said so!", MessageId = "XYZ", Scope = "namespace", Target = "XYZ.Blah")]
And lastly... all this will be fruitless unless you include the 'CODE_ANALYSIS' symbol in your build. Go to Properties>Build and add the conditional compilation symbol.
Acryonyms aren't meant to be all upper case in .NET naming conventions. For example HttpResponse etc.
From the capitalization conventions:
Casing of acronyms depends on the length of the acronym. All acronyms are at least two characters long. For the purposes of these guidelines, if an acronym is exactly two characters, it is considered a short acronym. An acronym of three or more characters is a long acronym.
The following guidelines specify the proper casing for short and long acronyms. The identifier casing rules take precedence over acronym casing rules.
Do capitalize both characters of two-character acronyms, except the first word of a camel-cased identifier.
A property named DBRate is an example of a short acronym (DB) used as the first word of a Pascal-cased identifier. A parameter named ioChannel is an example of a short acronym (IO) used as the first word of a camel-cased identifier.
Do capitalize only the first character of acronyms with three or more characters, except the first word of a camel-cased identifier.
A class named XmlWriter is an example of a long acronym used as the first word of a Pascal-cased identifier. A parameter named htmlReader is an example of a long acronym used as the first word of a camel-cased identifier.
If you were checking names via StyleCop, you could use StyleCop+ (custom rules) which supports configurable abbreviations list.

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.

CamelCase conversion to friendly name, i.e. Enum constants; Problems?

In my answer to this question, I mentioned that we used UpperCamelCase parsing to get a description of an enum constant not decorated with a Description attribute, but it was naive, and it didn't work in all cases. I revisited it, and this is what I came up with:
var result = Regex.Replace(camelCasedString,
#"(?<a>(?<!^)[A-Z][a-z])", #" ${a}");
result = Regex.Replace(result,
#"(?<a>[a-z])(?<b>[A-Z0-9])", #"${a} ${b}");
The first Replace looks for an uppercase letter, followed by a lowercase letter, EXCEPT where the uppercase letter is the start of the string (to avoid having to go back and trim), and adds a preceding space. It handles your basic UpperCamelCase identifiers, and leading all-upper acronyms like FDICInsured.
The second Replace looks for a lowercase letter followed by an uppercase letter or a number, and inserts a space between the two. This is to handle special but common cases of middle or trailing acronyms, or numbers in an identifier (except leading numbers, which are usually prohibited in C-style languages anyway).
Running some basic unit tests, the combination of these two correctly separated all of the following identifiers: NoDescription, HasLotsOfWords, AAANoDescription, ThisHasTheAcronymABCInTheMiddle, MyTrailingAcronymID, TheNumber3, IDo3Things, IAmAValueWithSingleLetterWords, and Basic (which didn't have any spaces added).
So, I'm posting this first to share it with others who may find it useful, and second to ask two questions:
Anyone see a case that would follow common CamelCase-ish conventions, that WOULDN'T be correctly separated into a friendly string this way? I know it won't separate adjacent acronyms (FDICFCUAInsured), recapitalize "properly" camelCased acronyms like FdicInsured, or capitalize the first letter of a lowerCamelCased identifier (but that one's easy to add - result = Regex.Replace(result, "^[a-z]", m=>m.ToString().ToUpper());). Anything else?
Can anyone see a way to make this one statement, or more elegant? I was looking to combine the Replace calls, but as they do two different things to their matches it can't be done with these two strings. They could be combined into a method chain with a RegexReplace extension method on String, but can anyone think of better?
So while I agree with Hans Passant here, I have to say that I had to try my hand at making it one regex as an armchair regex user.
(?<a>(?<!^)((?:[A-Z][a-z])|(?:(?<!^[A-Z]+)[A-Z0-9]+(?:(?=[A-Z][a-z])|$))|(?:[0-9]+)))
Is what I came up with. It seems to pass all the tests you put forward in the question.
So
var result = Regex.Replace(camelCasedString, #"(?<a>(?<!^)((?:[A-Z][a-z])|(?:(?<!^[A-Z]+)[A-Z0-9]+(?:(?=[A-Z][a-z])|$))|(?:[0-9]+)))", #" ${a}");
Does it in one pass.
not that this directly answers the question, but why not test by taking the standard C# API and converting each class into a friendly name? It'd take some manual verification, but it'd give you a good list of standard names to test.
Let's say every case you come across works with this (you're asking us for examples that won't and then giving us some, so you don't even have a question left).
This still binds UI to programmatic identifiers in a way that will make both programming and UI changes brittle.
It still assumes your program will only be used in one language. Either your potential market it so small that just indexing an array of names would be scalable enough (e.g. a one-client bespoke or in-house project), or you are assuming you will never be successful enough to need to be available to other languages or other dialects of your first-chosen language.
Does "well, it'll work as long as we're a failure" sound like a passing grade in balancing designs?
Either code it to use resources, or else code it to pass the enum name blindly or use an array of names, as that at least will be modifiable afterwards.

Categories