ReSharper 2024.2 Help
Code inspections in c#.
In C#, ReSharper 2024.2 provides two kinds of code inspections: 1148 inspections that detect errors such as broken syntax, unresolved symbols, compiler errors, and so on (you cannot configure or disable any of these inspections), and 943 proprietary code inspections , any of which you can disable or change its severity level . These code inspections help you detect code issues in design time in all open files, and additionally they allow you to find code issues in specific scope .
Configurable C# inspections are listed below, grouped by their categories .
Code Notification (2 inspections)
This category groups code inspections with minor severity levels.
Common Practices and Code Improvements (171 inspections)
This category groups inspections that hunt for medium severity issues that mainly affect code readability.
Compiler Warnings (194 inspections)
Inspections in this category detect compiler warnings before you compile.
Constraints Violations (11 inspections)
This category includes code inspections, mostly with the warning severity level, which detect violations related to symbol attributes, including ReSharper's code annotations , and other similar issues.
Entity Framework (8 inspections)
This category groups code inspections that validate usages of types and members from Entity Framework and their derivatives.
Formatting (41 inspections)
Inspections in this category detect code formatting problems .
Grammar Issues (4 inspections)
Inspections in this category report grammar issues in string literals and documentation comments.
Language Usage Opportunities (83 inspections)
This category includes code inspections, mostly with the suggestion severity level, which notify you when more advanced language constructs can be used. These inspections detect syntax of outdated language versions and suggest using features from more modern language versions. For most of the supported languages, language version can be detected automatically or set manually .
NUnit (30 inspections)
These inspections detect code issues related to NUnit tests.
Potential Code Quality Issues (201 inspections)
This category includes inspections that detect critical issues (code smells), mostly with Error or Warning level. This category also includes inspections that ensure localization assistance .
Redundancies in Code (96 inspections)
Code inspections in this category look for redundancies and dead code, which affect code readability and style, and could be safely removed. Some code redundancies cannot be fixed automatically, and quick-fixes for them are performed in the interactive mode, requiring the user input. But the majority of the redundancies can be fixed without user interaction, using either fix in scope or code cleanup .
Redundancies in Symbol Declarations (49 inspections)
This category includes code inspections, mostly with the warning severity level, which detect empty and unused symbol declarations.
Security (1 inspection)
Inspections in this category report NuGet packages that have vulnerabilities according to Checkmarks .
Spelling Issues (3 inspections)
These inspections detect typos in various contexts .
Syntax Style (46 inspections)
Inspections in this category detect violations of code syntax styles . In contrast to most code inspections, these inspections can either detect the same code construct as a code issue or not depending on the corresponding code style rule configured on the Code Editing | C# | Syntax Style page of ReSharper options Alt+R, O . You can also fix issues that these inspection detect using code cleanup .
Unreal Build System (2 inspections)
Inspections in this category are specific to Unreal Engine projects.
Xunit (1 inspection)
These inspections detect code issues related to xUnit.Net tests.
Lesson 6: Static Single Assignment
- discussion thread
- static single assignment
- SSA slides from Todd Mowry at CMU another presentation of the pseudocode for various algorithms herein
- Revisiting Out-of-SSA Translation for Correctness, Code Quality, and Efficiency by Boissinot on more sophisticated was to translate out of SSA form
- tasks due March 8
You have undoubtedly noticed by now that many of the annoying problems in implementing analyses & optimizations stem from variable name conflicts. Wouldn’t it be nice if every assignment in a program used a unique variable name? Of course, people don’t write programs that way, so we’re out of luck. Right?
Wrong! Many compilers convert programs into static single assignment (SSA) form, which does exactly what it says: it ensures that, globally, every variable has exactly one static assignment location. (Of course, that statement might be executed multiple times, which is why it’s not dynamic single assignment.) In Bril terms, we convert a program like this:
Into a program like this, by renaming all the variables:
Of course, things will get a little more complicated when there is control flow. And because real machines are not SSA, using separate variables (i.e., memory locations and registers) for everything is bound to be inefficient. The idea in SSA is to convert general programs into SSA form, do all our optimization there, and then convert back to a standard mutating form before we generate backend code.
Just renaming assignments willy-nilly will quickly run into problems. Consider this program:
If we start renaming all the occurrences of a , everything goes fine until we try to write that last print a . Which “version” of a should it use?
To match the expressiveness of unrestricted programs, SSA adds a new kind of instruction: a ϕ-node . ϕ-nodes are flow-sensitive copy instructions: they get a value from one of several variables, depending on which incoming CFG edge was most recently taken to get to them.
In Bril, a ϕ-node appears as a phi instruction:
The phi instruction chooses between any number of variables, and it picks between them based on labels. If the program most recently executed a basic block with the given label, then the phi instruction takes its value from the corresponding variable.
You can write the above program in SSA like this:
It can also be useful to see how ϕ-nodes crop up in loops.
(An aside: some recent SSA-form IRs, such as MLIR and Swift’s IR , use an alternative to ϕ-nodes called basic block arguments . Instead of making ϕ-nodes look like weird instructions, these IRs bake the need for ϕ-like conditional copies into the structure of the CFG. Basic blocks have named parameters, and whenever you jump to a block, you must provide arguments for those parameters. With ϕ-nodes, a basic block enumerates all the possible sources for a given variable, one for each in-edge in the CFG; with basic block arguments, the sources are distributed to the “other end” of the CFG edge. Basic block arguments are a nice alternative for “SSA-native” IRs because they avoid messy problems that arise when needing to treat ϕ-nodes differently from every other kind of instruction.)
Bril in SSA
Bril has an SSA extension . It adds support for a phi instruction. Beyond that, SSA form is just a restriction on the normal expressiveness of Bril—if you solemnly promise never to assign statically to the same variable twice, you are writing “SSA Bril.”
The reference interpreter has built-in support for phi , so you can execute your SSA-form Bril programs without fuss.
The SSA Philosophy
In addition to a language form, SSA is also a philosophy! It can fundamentally change the way you think about programs. In the SSA philosophy:
- definitions == variables
- instructions == values
- arguments == data flow graph edges
In LLVM, for example, instructions do not refer to argument variables by name—an argument is a pointer to defining instruction.
Converting to SSA
To convert to SSA, we want to insert ϕ-nodes whenever there are distinct paths containing distinct definitions of a variable. We don’t need ϕ-nodes in places that are dominated by a definition of the variable. So what’s a way to know when control reachable from a definition is not dominated by that definition? The dominance frontier!
We do it in two steps. First, insert ϕ-nodes:
Then, rename variables:
Converting from SSA
Eventually, we need to convert out of SSA form to generate efficient code for real machines that don’t have phi -nodes and do have finite space for variable storage.
The basic algorithm is pretty straightforward. If you have a ϕ-node:
Then there must be assignments to x and y (recursively) preceding this statement in the CFG. The paths from x to the phi -containing block and from y to the same block must “converge” at that block. So insert code into the phi -containing block’s immediate predecessors along each of those two paths: one that does v = id x and one that does v = id y . Then you can delete the phi instruction.
This basic approach can introduce some redundant copying. (Take a look at the code it generates after you implement it!) Non-SSA copy propagation optimization can work well as a post-processing step. For a more extensive take on how to translate out of SSA efficiently, see “Revisiting Out-of-SSA Translation for Correctness, Code Quality, and Efficiency” by Boissinot et al.
- One thing to watch out for: a tricky part of the translation from the pseudocode to the real world is dealing with variables that are undefined along some paths.
- Previous 6120 adventurers have found that it can be surprisingly difficult to get this right. Leave yourself plenty of time, and test thoroughly.
- You will want to make sure the output of your “to SSA” pass is actually in SSA form. There’s a really simple is_ssa.py script that can check that for you.
- You’ll also want to make sure that programs do the same thing when converted to SSA form and back again. Fortunately, brili supports the phi instruction, so you can interpret your SSA-form programs if you want to check the midpoint of that round trip.
- For bonus “points,” implement global value numbering for SSA-form Bril code.
IMAGES
VIDEO