Clang libtooling: determine macro expansion location - clang

I have a header header.h with a macro definition which expands into a class definition and a source file test.cpp which includes header.h and uses this macro. Then I use RecursiveASTVisitor to visit all CXXRecordDecl's.
When I visit the CXXRecordDecl which is expansion of the macro (in test.cpp) and query for its SourceLocation and dump() it, the location points to header.h - the location of macro definition.
What I need to get for this CXXRecordDecl is the SourceLocation of macro expansion - in my case it should be test.cpp.
Thanks in advance.

Found solution.
The required method is SourceManager's getFileLoc(SourceLocation loc), which "returns the expansion location" if loc "is a macro location".
My code to get source location for both normal class definitions and definitions as macro expansions:
bool VisitCXXRecordDecl(CXXRecordDecl* record)
{
SourceLocation loc = record->getLocStart();
SourceLocation locExp = m_sourceManager.getFileLoc(loc);
// if record is a macro expansion in test.cpp, locExp points to test.cpp
// if record is not a macro expansion, locExp correctly points to matching source file
}

Related

Does the using declaration allow for incomplete types in all cases?

I'm a bit confused about the implications of the using declaration. The keyword implies that a new type is merely declared. This would allow for incomplete types. However, in some cases it is also a definition, no? Compare the following code:
#include <variant>
#include <iostream>
struct box;
using val = std::variant<std::monostate, box, int, char>;
struct box
{
int a;
long b;
double c;
box(std::initializer_list<val>) {
}
};
int main()
{
std::cout << sizeof(val) << std::endl;
}
In this case I'm defining val to be some instantiation of variant. Is this undefined behaviour? If the using-declaration is in fact a declaration and not a definition, incomplete types such as box would be allowed to instantiate the variant type. However, if it is also a definition, it would be UB no?
For the record, both gcc and clang both create "32" as output.
Since you've not included language-lawyer, I'm attempting a non-lawyer answer.
Why should that be UB?
With a using delcaration, you're just providing a synonym for std::variant<whatever>. That doesn't require an instantiation of the object, nor of the class std::variant, pretty much like a function declaration with a parameter of that class doesn't require it:
void f(val); // just fine
The problem would occur as soon as you give to that function a definition (if val is still incomplete because box is still incomplete):
void f(val) {}
But it's enough just to change val to val& for allowing a definition,
void f(val&) {}
because the compiler doesn't need to know anything else of val than its name.
Furthermore, and here I'm really inventing, "incomplete type" means that some definition is lacking at the point it's needed, so I expect you should discover such an issue at compile/link time, and not by being hit by UB. As in, how can the compiler and linker even finish their job succesfully if a definition to do something wasn't found?

How to stop clang AST misinterpreting this type of function declaration as a variable declaration?

I am using clang's abstract syntax tree generation to generate an AST for some source files. It maps out normal functions great, however it trips up on some functions, mislabeling them as variable declarations. When it does this it waits for a semicolon to finish this declaration and so does not map out the rest of the source file following the problem function. Is there a way to make clang realize that it's a function definition, not a variable declaration?
I put a semicolon after the function definition and doing that makes clang ignore the contents of the function, but at least it generates nodes for the code following it in the source file. I'm using the prophy python interface to interact with clang in my scripts, but ran clang manually and found the same thing.
This is an example of a function that clang does map:
int killProcess(int pid)
{
int ret=1;
HANDLE pHandle;
if ((pHandle = OpenProcess(PROCESS_ALL_ACCESS,FALSE,pid)) != NULL)
if(!TerminateProcess(pHandle,0)) {
ret=0;
CloseHandle(pHandle);
}
return ret;
}
This is an example of a function which clang thinks is a variable declaration and ignores everything after it if there is no semicolon after the closing brace:
DWORD WINAPI listProcessesThread(LPVOID param)
{
char sendbuf[IRCLINE];
LPROC lproc = *((LPROC *)param);
LPROC *lprocp = (LPROC *)param;
lprocp->gotinfo = TRUE;
sprintf(sendbuf,"[PROC]: Listing processes:");
if (!lproc.silent) irc_privmsg(lproc.sock,lproc.chan,sendbuf,lproc.notice);
if (listProcesses(lproc.sock,lproc.chan,lproc.notice,NULL, FALSE, lproc.full) == 0)
sprintf(sendbuf,"[PROC]: Process list completed.");
else
sprintf(sendbuf,"[PROC]: Process list failed.");
if (!lproc.silent) irc_privmsg(lproc.sock, lproc.chan, sendbuf, lproc.notice);
addlog(sendbuf);
clearthread(lproc.threadnum);
ExitThread(0);
}
The expected results would be that clang knows that this is a function and generates a corresponding AST, however it doesn't. It constructs a VAR_DECL node with the spelling "WINAPI" instead of a "FUNCTION_DECL" node. The error it gives upon running "clang -cc1 -ast-dump processes2.cpp" is:
`-VarDecl 0x5625ad7ab2e0 col:7 invalid WINAPI 'int'
1 error generated.
At the end of its log. The abstract syntax tree up until this point is generated and displayed.
NB: I do not have WINAPI library installed because I am working on a Ubuntu machine.

'No matching constructor for initialization' Rad Studio 10 Clang Compiler

I have a snippet of code which compiles in C++ Builder XE8 using the classic BCC compiler. However, in Rad Studio 10 Seattle using the Clang compiler I get the error
'no matching constructor found for initialization of TChoiceItem'
Here is the snippet of code which causes the error.
LISTITEM_BEGIN( sch_TYPE_Choice )
LISTITEM_DATA( sch_TYPE_Daily, "Daily" )
LISTITEM_DATA( sch_TYPE_Weekly, "Weekly" )
LISTITEM_DATA( sch_TYPE_Monthly, "Monthly" )
LISTITEM_END()
Here is the code which defines TChoiceItem
//------------------------------------------------------------------------------
#define LISTITEM_BEGIN( Name ) TChoiceItem Name[] = {
//------------------------------------------------------------------------------
#define INT_LISTITEM_BEGIN( Name ) TIntChoiceItem Name[] = {
//------------------------------------------------------------------------------
#define LISTITEM_DATA( XCode, XText ) { XCode, 0, (char*)XText, 0 },
#define LISTITEM_DATA_NC( XShortText, XText ) { 0, (char*)XShortText, (char*)XText, 0 },
#define LISTITEM_DATA_EX( XCode, XShortText, XText ) { XCode, (char*)XShortText, (char*)XText, 0 },
#define LISTITEM_DATA_EX2( XCode, XShortText, XText, XDesc ) { XCode, (char*)XShortText, (char*)XText, (char*)XDesc },
#define LISTITEM_END() LISTITEM_DATA(0,0) };
I am fairly new to C++ so I am not exactly sure what to call the above method of defining a class/method.
Is this some sort of dated language feature not supported by the Clang compiler? Is there a way to modify the code or definition so the compiler will accept it?
Edit:
I found the actual declaration of the TChoiceItem class.
class TChoiceItem : public TChoiceBase
{
public:
char Code;
char *ShortText;
char *Text;
char *Desc;
};
It does't appear to have any sort of standard constructor at all. But somehow, everything still compiles and works with the classic BCC compiler.
Edit 2:
I found this question which looks to be describing a similar issue. Could it be that I need to include some kind of compiler flag when compiling the code? If so can I add a flag somehow in the embarcadero project compiler settings?
Using a list of values in braces to initialize the individual members of a class or struct is known as aggregate initialization.
As explained on cppreference.com, aggregate initialization isn't permitted if the class has a base class (among other restrictions). TChoiceItem inherits from TChoiceBase, so aggregate initialization isn't allowed (and the "classic" bcc32 compiler shouldn't have allowed it).
You have a couple of choices:
First, you can change the code to not inherit from TChoiceBase.
Second, you can define a constructor:
TChoiceItem(char code, char *short_text, char *text, char *desc)
: Code(code), ShortText(short_text), Text(text), Desc(desc) {}
C++11's uniform initialization means that your macros' syntax doesn't have to change: instead of braces meaning a list of values for individual members, the braces will mean a list of parameters to the constructor, but the result will be the same.

How do I define a macro with variadic method in objective-C?

The method I am trying to call is;
- (void)addLogWithLevel:(MDCLogLevel)logLevel logContent:(NSString *)logContent, ...
{
va_list args;
va_start(args, logContent);
NSString *message = [[NSString alloc] initWithFormat:logContent
arguments:args];
va_end(args);
MDCLog *log = [MDCLog logWithContent:message content:logLevel];
[self.deviceLogs addObject:log];
}
I have defined the macro as;
#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:(__VA_ARGS__)];
I have tried various formats of this macro, but nothing seems to work.
If I am to call;
MDCLogDebug(#"Test:%#", #"Hey");
All I see in the console is;
Hey
Where am I going wrong? I'm new to using Variadic methods and my C isn't so great!
Actually, your problem is not really related to Objective-C directly, but to C itself, as macros are plain C preprocessor directives.
In a macro, __VA_ARGS__ represents the arguments that are placed instead of the ....
So in your call to MDCLogDebug(#"Test:%#", #"Hey"), the format argument is #"Test:%#" and __VA_ARGS__ represents the rest of the arguments afterwards, namely simply #"Hey" in your case.
If you want to pass both the #"Test:%#" and #"Hey" as arguments to logContent:, you have to explicitly tell it so, using:
#define MDCLogDebug(format, ...) [[MDCLogController sharedController] addLogWithLevel:MDCLogLevelDebug logContent:format, __VA_ARGS__]
Note: An even better solution would be to use the ## prefix before __VA_ARGS__ so that the comma won't be added if __VA_ARGS__ is empty (namely if you only pass a format argument but nothing afterwards, like MDCLogDebug(#"Foo")):
#define MDCLogDebug(format, ...) [[MDCLogController sharedController] \
addLogWithLevel:MDCLogLevelDebug \
logContent:format, ## __VA_ARGS__]
(Note: I use backslashes in this last macro definition above to allow the macro to be written on multiple lines, instead of writing it on one single big long line)
For more information, see the official GCC documentation about Variadic Macros here.

Which is the best way to suppress "unused variable" warning

There are 3 (which I know) ways to suppress the "unused variable" warning. Any particular way is better than other ?
First
- (void)testString:(NSString *)testString
{
(void)testString;
}
Second
- (void)testString:(NSString *)__unused testString
{
}
Third
- (void)testString:(NSString *)testString
{
#pragma unused(testString)
}
This is the approach I use: cross platform macro for silencing unused variables warning
It allows you to use one macro for any platform (although the definitions may differ, depending on the compiler), so it's a very portable approach to express your intention to popular compilers for C based languages. On GCC and Clang, it is equivalent of wrapping your third example (#pragma unused(testString)) into a macro.
Using the example from the linked answer:
- (void)testString:(NSString *)testString
{
MONUnusedParameter(testString);
}
I've found this approach best for portability and clarity, in use with some pretty large C, C++, ObjC, and ObjC++ codebases.
If you are compiling with GCC, you can take advantage of attribute extensions to set the 'unused' attribute. Like this:
int somevar __attribute__((unused));
It also works for unused parameter warnings (-Wunused-parameter)
To make it shorter to write I am using this macro:
#define _U_ __attribute__((unused))
And declare like this:
int somevar _U_ ;
One way to do it is just to assign a variable pointlessly after it is declared For example:
int foo;
foo = 0;
This should suppress the unused variable warning. It is just a pointless assignment.
But otherwise I would agree with ouah, the first method is the most reliable, if you must choose from those three.

Resources