"Method body is too complex to analyze, consider decomposing it"

Since upgrading to Resharper 9, I've started getting a lot of inspection warnings that say "Method body is too complex to analyze, consider decomposing it", even on methods that aren't particularly complex (a couple have only a dozen or so lines of code with no if or while statements). What does this warning mean? Should I worry about it, or just turn it off? Thanks!

17 comments
Comment actions Permalink

Assuming that R# is doing cyclomatic complexity analysis on your methods, it's quite possible it's still very high cyclo. LINQ statements can have extremely high cyclomatic complexity, similar with IQueryable types since the parsers for the lambda expressions are obnoxiously difficult and lots of work requires loops in loops.

If you really feel a method it is suggesting as too complex is no where near right, it would be great if you could include some source to see if it happens for others or whether it's localized to your machine.

Also dependency injection containers could be injecting lazily computed factories that are adding to complexities, especially if you're causing it to generate discrete objects on each touch. This wouldn't seem to be a normal scenario, but it's a possiblity. A more likely scenario is you have callA callB callC callA callD callB callE callE callF callF all happening in original callA which becomes literally recurisve or recurisive-like with all the stack bouncing.

0
Comment actions Permalink

While some of the 100s of methods that R# is now saying are "too complex to analyze" are indeed quite complex, many are extremely simple, such as this one:

public static bool operator ==(Quad quad1, Quad quad2)
 {
      return quad1.Equals(quad2);
 }

There's nothing remotely fancy going on here. Quad is simply a value type, and the Equals method that is being called implements the IEquatable<Quad> interface.

Additionally, previous versions of R# never flagged *any* methods, even the extremely complex ones, as "too complex to analyze", so either previous versions didn't surface this error, or there has been some sort of regression in the latest version.

Thanks for your help!

0
Comment actions Permalink

I would suggest clearing the cache (ReSharper -> Options -> General -> Clear Caches, and then restart Visual Studio). Something's gone wrong if it's flagging that operator method as too complex...

0
Comment actions Permalink

Thanks for the advice, but unfortunately clearing the cache (and restarting Visual Studio) didn't work.

For the record, this happens on two different computers, both Windows 7 64-bit running Visual Studio 2013 Update 4 and Resharper 9.0 Update 1.

I tried doing a full uninstall (including removing everything in AppData and the registry that I could find) and reinstall, but that didn't work either. I also tried turning off all my custom R# settings, but that didn't help.

Any other ideas? Is there any diagnostic info I can provide you with? Thanks.

0
Comment actions Permalink

You can try enabling the log file. Start Visual Studio with the command "devenv /ReSharper.Internal". Go to Options -> Logging and click "Create File" for the Common logger. Then click "Edit File" to open the config file in the text editor - we need to enable the file logger (by default it logs to the debugger). Uncomment the "file" appender element near the top of the file, then uncomment the "file" "appender-ref". Restart Visual Studio, get it to fail, close Visual Studio and check the log file at c:\logs\resharper-{date}.log. You can email me the log at matt.ellis at jetbrains.com.

Do you have a repro project that we could take a look at and try and debug?
 

0
Comment actions Permalink

I also have that message

not to mention that r# 8.2 didnt tell me nothing about the same method

I have this on my windows 8.1 64 bit ( vs 2012)

This is the only reason why I uninstalled 9 and back to 8.2

as soon as it fixed ,I will come back to 9.

For jetbrains guys , if you need RDP in order to solve - be my guess. jsut ask : namir.78 at sergey and larry company.

0
Comment actions Permalink

Just posting to make sure you received my email with the log file and repro project, since I
haven't heard back.

Thanks much!

0
Comment actions Permalink

Hi, yes, thanks, I got the code, and it repros as expected. It turns out this is a change that was introduced in ReSharper 9.0, but it's actually not really a change in behaviour. The control flow analyser in ReSharper 8 would also fail to analyse the method you pointed out. This is due to the method actually being rather complex - loops with if statements generate a lot of internal states in the analyser. Previously, ReSharper 8 would silently ignore it. The change in 9 is to display this as a warning, to highlight that ReSharper is unable to perform a full analysis of this method, and therefore not provide all expected warnings, such as dead code analysis, etc. You can see more in the comments to this issue: https://youtrack.jetbrains.com/issue/RSRP-428865

I did notice an exception thrown when looking at the Quad type, though, and I've passed that on to the dev team to follow up on. You can track the issue here.

0
Comment actions Permalink

Great, so glad that project was useful!

So my understanding is that *some* of those methods are legitimately too complex and R# is now giving a warning (IMHO a good behavior), while some others are an actual bug in R# 9. Correct?

Thanks for looking into this! I'm looking forward to seeing the bug fixed in future versions. :-)

0
Comment actions Permalink

Well, I'm going be cagey :)

One is legitimate behaviour. The second (e.g. equality operators being too complex) might be a bug, or it might have an interesting reason behind it, based on comparing structs, and those structs have issues with the complexity of e.g. the constructors. Also, there were exceptions thrown in the log file, those are definitely wrong, and they will be fixed, but I don't know what impact they'll have on this project.

0
Comment actions Permalink

I think this feature is pretty sketchy. I finally saw it in live code and where it popped up i can make it come and go away by commenting a single line out (that is almost identical to the line before it).

I can also make it go away by extracting less than 10 lines to another method.

So this feature certainly isn't calculating cyclomatic complexit because that wouldn't be reduced by extracting a method.

I can also make it go away by deleting a line where i null check a set of variables.

My method is a total of 23 lines include whitespace, a total of 19 without whitespace.

0
Comment actions Permalink

Extracting a method should make it go away, because you're reducing the combination of number of statements, loops, branches and variable states in the method. Once this combination gets over a certain threshold, it becomes too expensive to calculate further, and the warning is displayed. The functionality is what's used to calculate redundant code, null analysis, value tracking, function entry/exit points, and so on. It's building a control flow graph, rather than just calculating cyclomatic complexity - which is based on the control flow graph, but doesn't require the entire structure to be maintained. It's been used in previous versions of ReSharper, but the warning is new to 9.0 - the analysis has always had these limits, but it was never reported to the user. But it makes sense that we do so - ReSharper can't provide full functionality for this method, and that is worth reporting, and if it's too complex for analysis, it's also likely worth refactoring to a less complex form.

0
Comment actions Permalink

Assume you mean it should NOT go away by extracting a method.

In my case it most certainly does. Since i hate to be nagged by resharper i just left the code in the meaningless method so it doesn't bother me.

0
Comment actions Permalink

No, it *should* go away, because you're removing code from that method, so reducing the complexity.

0
Comment actions Permalink

I'm getting the same thing. I realize that some of my methods are too complex (which sometimes I keep them that way as to not have so many methods on an application that needs to be fast and responsive...but that's debatable ;)). This one particular one has me puzzled though. Maybe because there are so many arguments being passed in? This is a method that is called on a webpage that is doing a search. This is passed to a service->repository->linq2entities. I didn't see a good reason to create a model just for this, just to do the exact same thing while creating the model and then in the repository doing the same redundant work, but extracting it from the model. Anyone care to enlighten me? :D

 
protected List<TrackingNumberStatus> GetTrackingNumberStatusFiltered(int projectid, string trackingNumber,
                     string carrierCodes,
                     DateTime? shipmentDateBegin,
                     DateTime? shipmentDateEnd,
                     string status,
                     string statusDescription,
                     DateTime? statusDateBegin,
                     DateTime? statusDateEnd,
                     bool? exceptionsOnly,
                     DateTime? exceptionDateBegin,
                     DateTime? exceptionDateEnd,
                     bool? exceptionDateIsNull,
                     DateTime? exceptionReleaseDateBegin,
                     DateTime? exceptionReleaseDateEnd,
                     bool? exceptionReleaseDateIsNull,
                     DateTime? commentsLastUpdatedOnBegin,
                     DateTime? commentsLastUpdatedOnEnd,
                     bool? commentsLastUpdatedOnIsNull,
                     string commentsLastUpdatedBy,
                     bool? priorityOnly,
                     ShipmentType shipmenttype)
        {
            return this._customerorderservice.GetTrackingNumberStatusFiltered(projectid, trackingNumber, carrierCodes,
                      shipmentDateBegin,
                      shipmentDateEnd,
                      status,
                      statusDescription,
                      statusDateBegin,
                      statusDateEnd,
                      exceptionsOnly,
                      exceptionDateBegin,
                      exceptionDateEnd,
                      exceptionDateIsNull,
                      exceptionReleaseDateBegin,
                      exceptionReleaseDateEnd,
                      exceptionReleaseDateIsNull,
                      commentsLastUpdatedOnBegin,
                      commentsLastUpdatedOnEnd,
                      commentsLastUpdatedOnIsNull,
                      commentsLastUpdatedBy,
                      priorityOnly,
                      shipmenttype);
        }
0
Comment actions Permalink

Yes, the warning here is due to the number of arguments, but also due to the fact that a lot of the arguments are structs. The control flow analysis is a function of the parameters, variables, branches, but also the fields in a struct. The more items there are, the more expensive the analysis is to calculate, and this example hits the limits of the analysis. Because we use the control flow analysis to provide other warnings - null analysis, dead code, etc., if we don't have it, we can't provide these other analyses. The limits were there in previous versions, but we made the warning visible in 9.0, so the user would be aware that other control flow analysis was not being performed, and because, well, the methods are complex (and it's a warning, which of course means you're free to ignore it). However, we've decided that we're going to hide this warning by default in 9.1. We don't like the fact that we're warning you that your code has hit the limits of our analysis - we'd rather fix the limits. Also, because the factors that make up the analysis aren't always obvious (e.g. fields of struct parameters), the warning message can lead to confusion. So, we're reverting back to pre-9.0 behaviour - the limits will still be reached, but we no longer display this warning.

0
Comment actions Permalink

Ah okay that makes sense. I didn't think about the structures. Also my last argument is a class. While not too complex, it does add even more to the complexity along with the other structs. I understand better now, but it is true that it isn't very explicit on what it is sometimes. Other times yes though. Thanks for feedback and for the great tools. Really appreciate it.

0

Please sign in to leave a comment.