how can I compare two decls in clang? - clang

Besides simply get and check the decls' name, are there some methods in clang to compare whether two or more decls (clang::Decl) are same or not?

Related

How do I get the pointer associated with a node in the ClangAST using the c++ API?

When you dump the AST of a C program using clang, each node in the tree has a unique hexcode.
https://stephenwzl.github.io/images/ast-dump.png
For example, x in the above image has 0x7efcf7017538.
I am trying to do some calculations based on the AST of C programs. I need to be able to connect variable references with their previous use and assignments. I think the best way to do this is to use the unique hexcode clang assigns to a VarDecl. I've tried looking through the clang API and reverse engineering the dump function, but i can't seem to find how this value is stored. I'm using the recursive visitor to walk the tree. Is there a variable I have to reference for a node or a function I have to call on a node?
So, it looks like it's literally just the actual pointer to the stmt, decl, etc.
So, if you have a stmt* s and you want to get the pointer, simply cout s

Find clang::Type in Clang AST by name

In Clang AST, is it possible to find type by name?
For example I have qualified name : nspace::my_type<int, 10u>. How can I check if type is present in current translation unit?
NOTE: my knowledge is extremely limited from just once writing a clang tidy check to do some update I needed. Might be wrong.
There are two possible things that you might need in clang AST depending on the task at hand: Type and TypeLocation. I needed the type location, so this is what I'll mention first.
Find the type spelling.
In this case what you actually want is the TypeLocation ast nodes. They represent a spelling of a type.
Unfortunately are not printed by clang-query.
The way to search for them is by using a type_loc matcher.
This is from something I needed: find all specialisations of a wide template.
This would find me all the spellings of wide<T>
l isWide hasDeclaration(classTemplateDecl(namedDecl(hasName("wide"))))
l isWideSpec templateSpecializationType(isWide)
l wideLoc typeLoc(loc(isWideSpec))
wideLoc - is what I was using to change the spelling of the type.
Different type_loc have parents that are also type_loc.
So for example I can find all entries of T unless they are inside wide<T>
typeLoc(loc(asString("T")), unless(hasAncestor(wideLoc)))
Find all of the actual usages of the type, regardless of how it is spelled.
Now for this type of problem you'd need to match on a type.
Have never done this myself, but we can see abseil doing this for example here:
https://github.com/llvm/llvm-project/blob/b426b45d101740a21610205ec80610c6d0969966/clang-tools-extra/clang-tidy/abseil/UpgradeDurationConversionsCheck.cpp#L36
PS. Just in case - all clang ast matchers:
https://clang.llvm.org/docs/LibASTMatchersReference.html

Check multiple conditions at once using m4 preprocessor

There is any m4 syntax that is equivalent to this C preprocessor one?
#if defined A || defined B
do something
#endif
The short answer is no.
The long answer:
Checking if macros are defined
define(`defined', `ifelse($1()$1, `$1()$1', ``0'', ``1'')')
ifelse(eval(defined(`A') || defined(`B')),
1,
``At least one is defined'',
``Neither are defined'')
There are no sensible ways to check for a defined macro in m4, so you would have to resort to hacks like the above.
How it works
ifelse checks for equality of two strings. In the defined macro, I've expanded the macro in $1 twice (once as $1(), once as $1). I'm comparing it against $1()$1 as a string, so if it doesn't expand then it will compare true. The reason for specifying the macros in two different ways is because A could be defined as ``A'' or ``A()'' which would otherwise cause false negatives when using this method to check whether or not it is defined.
I'm then using that defined macro within an eval to throw the || logic on top.
Caveats
If you use the word defined in your document already, you might want to give the macro a different name.
The defined macro will not work on macros defined to expand to unquoted syntactic markers like (, ,, or ).
If the macro to be checked is infinitely recursive, the defined check will also never return. (Essentially, realize that a hack like this is still actually executing the macro.)
Though the last 2 points there are something you'd expect from any ifelse check on a macro, it might not be intuitive to expect it from a macro purporting to check for whether another macro is defined.
A better way
I would much rather suggest that you define the variables with some default value first, and just avoid the problem of checking whether it is defined or not altogether.
This is much easier to do:
# Define this right off the bat:
define(`A', ``0'')
# Maybe later this line will come up...
# Quotes around the A are mandatory
define(`A', ``1'')
# Then soon after that, you can check:
ifelse(A, `0', , ``hey, A is nonzero!'')

How to specify a placeholder for things like user-defined types in yacc?

When using yacc, we specify patterns like
type : builtInType
| userDefinedType
builtInType is quite easy, because we can just list them all; but userDefinedType is a dynamic part, what's in this set is determined by what types are defined before in the source file.
How can I specify the pattern for userDefinedType?
For something like that you would simply use the identifier token for userDefinedType. It is not known in advance which identifiers refer to user-defined types and which do not, so you have few other options.
The determination as to what type is being referenced and whether it is legal in context is often deferred to the semantic analysis phase.

Pointer to generic type

In the process of transforming a given efficient pointer-based hash map implementation into a generic hash map implementation, I stumbled across the following problem:
I have a class representing a hash node (the hash map implementation uses a binary tree)
THashNode <KEY_TYPE, VALUE_TYPE> = class
public
Key : KEY_TYPE;
Value : VALUE_TYPE;
Left : THashNode <KEY_TYPE, VALUE_TYPE>;
Right : THashNode <KEY_TYPE, VALUE_TYPE>;
end;
In addition to that there is a function that should return a pointer to a hash node. I wanted to write
PHashNode = ^THashNode <KEY_TYPE, VALUE_TYPE>
but that doesn't compile (';' expected but '<' found).
How can I have a pointer to a generic type?
And adressed to Barry Kelly: if you read this: yes, this is based on your hash map implementation. You haven't written such a generic version of your implementation yourself, have you? That would save me some time :)
Sorry, Smasher. Pointers to open generic types are not supported because generic pointer types are not supported, although it is possible (compiler bug) to create them in certain circumstances (particularly pointers to nested types inside a generic type); this "feature" can't be removed in an update in case we break someone's code. The limitation on generic pointer types ought to be removed in the future, but I can't make promises when.
If the type in question is the one in JclStrHashMap I wrote (or the ancient HashList unit), well, the easiest way to reproduce it would be to change the node type to be a class and pass around any double-pointers as Pointer with appropriate casting. However, if I were writing that unit again today, I would not implement buckets as binary trees. I got the opportunity to write the dictionary in the Generics.Collections unit, though with all the other Delphi compiler work time was too tight before shipping for solid QA, and generic feature support itself was in flux until fairly late.
I would prefer to implement the hash map buckets as one of double-hashing, per-bucket dynamic arrays or linked lists of cells from a contiguous array, whichever came out best from tests using representative data. The logic is that cache miss cost of following links in tree/list ought to dominate any difference in bucket search between tree and list with a good hash function. The current dictionary is implemented as straight linear probing primarily because it was relatively easy to implement and worked with the available set of primitive generic operations.
That said, the binary tree buckets should have been an effective hedge against poor hash functions; if they were balanced binary trees (=> even more modification cost), they would be O(1) on average and O(log n) worst case performance.
To actually answer your question, you can't make a pointer to a generic type, because "generic types" don't exist. You have to make a pointer to a specific type, with the type parameters filled in.
Unfortunately, the compiler doesn't like finding angle brackets after a ^. But it will accept the following:
TGeneric<T> = record
value: T;
end;
TSpecific = TGeneric<string>;
PGeneric = ^TSpecific;
But "PGeneric = ^TGeneric<string>;" gives a compiler error. Sounds like a glitch to me. I'd report that over at QC if I was you.
Why are you trying to make a pointer to an object, anyway? Delphi objects are a reference type, so they're pointers already. You can just cast your object reference to Pointer and you're good.
If Delphi supported generic pointer types at all, it would have to look like this:
type
PHashNode<K, V> = ^THashNode<K, V>;
That is, mention the generic parameters on the left side where you declare the name of the type, and then use those parameters in constructing the type on the right.
However, Delphi does not support that. See QC 66584.
On the other hand, I'd also question the necessity of having a pointer to a class type at all. Generic or not. they are needed only very rarely.
There's a generic hash map called TDictionary in the Generics.Collections unit. Unfortunately, it's badly broken at the moment, but it's apparently going to be fixed in update #3, which is due out within a matter of days, according to Nick Hodges.

Resources