Whole Tomato Software Forums
Whole Tomato Software Forums
Main Site | Profile | Register | Active Topics | Members | Search | FAQ
 All Forums
 Visual Assist
 Technical Support
 Find references misses some matches when #if used

You must be registered to post a reply.
Click here to register.

Screensize:
UserName:
Password:
Format: BoldItalicizeUnderlineStrikethrough Align leftCenterAlign right Insert horizontal ruleUpload and insert imageInsert hyperlinkInsert email addressInsert codeInsert quoted textInsert listInsert Emoji
   
Message:

Forum code is on.
Html is off.

 
Check to subscribe to this topic.
   

T O P I C    R E V I E W
DWS Posted - Sep 18 2024 : 11:39:37 AM
Hello, I have attached (via Google Drive) a ZIP of a simple Visual Studio 2022 solution which demonstrates my problem.

https://drive.google.com/file/d/14iZvkWimN1HXUTesCLbOHL-aGj4sHPfZ/view?usp=drive_link

The source files are:

  • structs.h - Defines two struct types, InactiveStruct_t and ActiveStruct_t. Importantly, both structs contain a field that has the same name, fieldWithSameName. Also, InactiveStruct_t is defined within an #if (0) preprocessor block.

  • testClass.h - The test class has two functions and a data member named activeStruct, of type ActiveStruct_t.

  • function1.cpp contains TestClass::Function1(), which assigns "activeStruct.fieldWithSameName" to zero.

  • function2.cpp contains TestClass::Function2(), which has the same body as Function1(). Importantly, function2.cpp also contains an #if (0) preprocessor block, which declares a variable named "activeStruct" which -- if it was not being excluded from compilation -- would "hide" the assignment to TestClass::activeStruct in Function2().

To demonstrate the problem, perform a Find References on ".fieldWithSameName" in the two functions. You should see the following:
  • In TestClass::Function1(), find references returns the assignment to activeStruct.fieldWithSameName in Function1. It also returns the field named "fieldWithSameName" in ActiveStruct_tag. This is correct.

  • In TestClass::Function2(), find references returns the assignment to activeStruct.fieldWithSameName in Function2 (correct). But it also returns the field named "fieldWithSameName" in InactiveStruct_tag. This is incorrect.
5   L A T E S T    R E P L I E S    (Newest First)
feline Posted - Sep 20 2024 : 10:02:56 AM
There are a couple of approaches, but I would approach these sort of tricks with GREAT CARE!!!

First, the easy one. If you are doing something simple like above, VA will either take the first or last definition it sees. I never remember which way around it is, since its something I need to check so very rarely. But if you run a couple of tests you should see consistent behaviour. Then its "just" a matter of having consistent ordering.

The second approach is to create a file called "va_stdafx.h" and place it in the same directory as your SLN file. VA specifically looks for this file, and parses it before it parses anything else when rebuilding its symbol database.

Normally I use this file to help work around odd macro problems, by making sure the macro definition I want is the first one VA see's, and gives priority to. But you COULD try putting some of these things here. But any changes to the file will only take effect after doing a VA symbol database rebuild, which can be triggered via:

VA Options -> Performance -> Rebuild symbol databases

and restarting Visual Studio.

I am not sure if this would actually do what you want here, but it is a file you can look into. Please note the file needs to end with a blank line, when editing it.


A longer term thought, we are considering getting VA to respect preprocessor branches, so it only parses the "live" code. Obviously there are going to be some interesting edge cases with this, especially since we don't get to run a pre-processor, but it might help you if ever done, but it isn't a short term solution:

case=42316
DWS Posted - Sep 19 2024 : 2:31:07 PM
Thank you for your answer -- I was afraid that might be the case, but it's understandable.

Our C++ code is highly shared between multiple build configurations, and therefore the situation where we are using one or more #if conditions to selectively choose between different structures that have at least some overlap in the names of their fields is not uncommon for us (although I know in the grand scheme of things that people don't do this kind of thing all that often). We're not using #if(0) like in this simple example, but rather #if(CONFIG_ONE) #elif(CONFIG_TWO), etc.

I'll have to give some thought to whether there is any way to refactor parts of our software so that this is done less frequently, but still somehow without requiring us to duplicate pieces of our code. The problem is that right now we can't always trust that our Find References results are complete (although at least now I understand why that is). And of course, Find References is one of the ways that we use VA the most.

I guess I might as well ask one final follow-up question: You said that if there are two possible definitions of a symbol, VA will ultimately pick one of them to use. Is there anything creative that we could do to influence the decision that VA makes in this regard? Maybe another way of asking the question is, is there anything that we can do inside of a preprocessor block that will have some effect on how VA parses the code? If so, we might be able to find some clever way to use it to work around our problem. Thanks!
feline Posted - Sep 19 2024 : 1:11:20 PM
Unfortunately VA simply isn't designed to do this. If there are two possible definitions of the symbol, one will get picked and used.

Do you have a lot of situations like this, or only a few?

I am wondering if marking these types with Hashtags would work. If you mark the symbols with the same hashtag, you can jump between the instances of the hashtag with Alt-G on any of them.

https://www.wholetomato.com/documentation/navigation/va-hashtags
DWS Posted - Sep 19 2024 : 11:11:56 AM
You're right; I don't want VA to ignore the code in the #if (0) block (although that is how I phrased my initial post -- my fault).

What I really want is for VA to account for the possibility that activeStruct in Function2 could be either an InactiveStruct_t (as if the preprocessor code were included) or an ActiveStruct_t (when the preprocessor code is excluded).

So in Function2(), I would want find references to return all references to both:
  • InactiveStruct_t::fieldWithSameName
  • ActiveStruct_t::fieldWithSameName

As it is today, it only returns references to InactiveStruct_t::fieldWithSameName.


I thought that maybe changing the #if to the following would make it return references to both structs:
#if (0)
InactiveStruct_t activeStruct;
#else
ActiveStruct_t activeStruct;
#endif

But unfortunately, it seems to just make VA assume that activeStruct in Function2 is of type ActiveStruct_t, rather than InactiveStruct_t -- it doesn't return references to both InactiveStruct_t::fieldWithSameName and ActiveStruct_t::fieldWithSameName.

Thanks for your continued help! -- Dave
feline Posted - Sep 19 2024 : 07:45:04 AM
Do you want VA to ignore the code in the #if (0) block?

By design, VA parses inactive code, since if you are working under Windows, you are still going to want help working on code wrapped in a #ifdef LINUX block. So currently VA is doing what we expect and want.

If you really want VA to ignore this code, you can change:

#if (0)
InactiveStruct_t activeStruct;
#endif

into:
#if (0)
_asm {
InactiveStruct_t activeStruct;
}
#endif


since VA's parser ignores anything inside the _asm block, and since the compiler is already ignoring this code, editing the code further doesn't effect things.

© 2023 Whole Tomato Software, LLC Go To Top Of Page
Snitz Forums 2000