Can Clang AST get the virtual function table? - clang

I tried using CXXRecordDecl, to print the virtual functions, but they are in declaration order, which may not be the order actually in the vtable.
sample code
namespace test
{
class Foo {
public:
virtual void v_func() {}
virtual void v_func2() {}
virtual ~Foo() = default;
};
class Bar : public Foo {
public:
virtual void v_func2() {}
virtual void v_func() {}
virtual ~Bar() = default;
};
} // namespace test
int main() {
test::Foo *foo = new test::Bar();
test::Bar *bar = new test::Bar();
delete foo;
delete bar;
return 0;
}
The virtual function table printed by gdb is as follows:
(gdb) info vtbl foo
vtable for 'test::Foo' # 0x65a450 (subobject # 0x101a008):
[0]: 0x404402 <test::Bar::v_func()>
[1]: 0x4043f4 <test::Bar::v_func2(int, test::tmp)>
(gdb) info vtbl bar
vtable for 'test::Bar' # 0x65a450 (subobject # 0x101a010):
[0]: 0x404402 <test::Bar::v_func()>
[1]: 0x4043f4 <test::Bar::v_func2(int, test::tmp)>
By traversing the method of CXXRecordDecl, it can only print in the order of function declaration.
// CXXRecordDecl *cxx_record
// Dump out all the virtual methods
for (CXXRecordDecl::method_iterator first = cxx_record->method_begin();
first != cxx_record->method_end(); ++first) {
if (!first->isVirtual()) {
continue;
}
llvm::outs() << first->getQualifiedNameAsString() << " " << first->getType().getAsString() << "\n";
}
out:
v_func void (void)
v_func2 void (int, class test::tmp)
~Foo void (void) noexcept
v_func2 void (int, class test::tmp)
v_func void (void)
~Bar void (void) noexcept
I checked the documentation for CXXRecordDecl and found nothing related to vtables

Related

Getting inheritance issues when trying to compile

I have a class called stackTester that is trying to inherit from another class stackofChars. The methods defined in stackofChars that I am trying to use in stackTester are all virtual, but when I try to use them in stackTester, I get an error
request for member which is of non-class type
Here is my stackofChars.h file:
#define STACK_OF_CHARS_H
#include "node.h"
class stackofChars
{
private:
node* m_top;
public:
//constructor for the stack, takes in no paramaters
stackofChars();
//copy constructor, takes in a referance to the original stack
stackofChars(const stackofChars& orig);
//destructor for the stack, no parameters
~stackofChars();
//destructor for the copy, takes in a referance to the copy
void operator=(const stackofChars& rhs);
//pushes the stack back and creates a new node at the stop, takes in an entry, returns nothing
virtual void push(char entry);
//deletes the top entry and pushes the stack up, takes in nothing, returns nothing
virtual void pop();
//peeks at the top entry, takes in nothing, returns a char, const because nothing is changed
virtual char peek() const;
//checks if the stack is empty, takes in no parameters, returns nothing, const because nothing is changed
virtual bool isEmpty() const;
};
#endif
Here is my stackTester.h file:
#ifndef STACK_TESTER_H
#define STACK_TESTER_H
#include "stackofChars.h"
class stackTester : public stackofChars
{
public:
stackTester();
//This will call all your test methods
void runTests();
private:
//Creates an empty stack and verifies isEmpty() returns true
void test1();
//Creates an empty stack pushes 1 value, verifies isEmpty() returns false
void test2();
//Creates an empty stack, then pushes once, pops once, and verifies isEmpty returns true
void test3();
//more test methods as needed
};
#endif
If needed, here is my stackTester.cpp file:
#include "stackTester.h"
#include "stackofChars.h"
#include <iostream>
void stackTester::test1()
{
stackofChars test();
std::cout << "Test#1: Newly created stack is empty: ";
if(test.isEmpty() == true)
{
std::cout << "Pass\n";
}
else
{
std::cout << "Fail\n";
}
}
void stackTester::test2()
{
stackofChars test();
test.push(???);
std::cout << "Test#2: Push on empty stack makes it non-empty: ";
if(test.isEmpty() == true)
{
std::cout << "Pass\n";
}
else
{
std::cout << "Fail\n";
}
}
void stackTester::test3()
{
stackofChars test();
test.push(???);
test.pop();
std::cout << "Test#3: Popping all elements makes stack empty: ";
if(test.isEmpty() == true)
{
std::cout << "Pass\n";
}
else
{
std::cout << "Fail\n";
}
}
Can someone tell me why I am getting this error?
stackofChars test(); is wrong.The right way to declare a class object should be: stackofChars test; or stackofChars test{};
There is an explanation here enter link description here

How to convert a GLib.Value of type GStrv (string[]) to a GLib.Variant

In the following example one class property is of type Gstrv.
With ObjectClass.list_properties() one can query the Paramspec of all properties, and with get_property() all properties can be requested as GLib.Value. How would I access the Value of type GStrv and convert it to a GLib.Variant?
My GLib version is slightly outdated, so I do not have the GLib.Value.to_variant() function available yet :( .
public class Foo: GLib.Object {
public GLib.HashTable<string, int32> bar;
public Foo() {
bar = new GLib.HashTable<string, int32>(str_hash, str_equal);
}
public string[] bar_keys { owned get { return bar.get_keys_as_array(); } }
}
int main() {
var foo = new Foo();
Type type = foo.get_type();
ObjectClass ocl = (ObjectClass) type.class_ref ();
foreach (ParamSpec spec in ocl.list_properties ()) {
print ("%s\n", spec.get_name ());
Value property_value = Value(spec.value_type);
print ("%s\n", property_value.type_name ());
foo.get_property(spec.name, ref property_value);
// next: convert GLib.Value -> GLib.Variant :(
}
foo.bar.set("baz", 42);
return 0;
}
Output:
bar-keys
GStrv
Using GLib.Value.get_boxed() seems to be working.
Example:
// compile simply with: valac valacode.vala
public class Foo: GLib.Object {
public GLib.HashTable<string, int32> bar;
public Foo() {
bar = new GLib.HashTable<string, int32>(str_hash, str_equal);
}
public string[] bar_keys { owned get { return bar.get_keys_as_array(); } }
}
public Variant first_gstrv_property_as_variant(Object obj)
{
Type class_type = obj.get_type();
ObjectClass ocl = (ObjectClass) class_type.class_ref ();
foreach (ParamSpec spec in ocl.list_properties ()) {
print ("%s\n", spec.get_name ());
Value property_value = Value(spec.value_type);
print ("%s\n", property_value.type_name ());
obj.get_property(spec.name, ref property_value);
// next: convert GLib.Value -> GLib.Variant
if(property_value.type_name () == "GStrv") {
return new GLib.Variant.strv((string[])property_value.get_boxed());
}
}
return new GLib.Variant("s", "No property of type GStrv found");
}
int main() {
var foo = new Foo();
print("%s\n", first_gstrv_property_as_variant(foo).print(true));
foo.bar.set("baz", 42);
print("%s\n", first_gstrv_property_as_variant(foo).print(true));
foo.bar.set("zot", 3);
print("%s\n", first_gstrv_property_as_variant(foo).print(true));
return 0;
}
Output:
bar-keys
GStrv
#as []
bar-keys
GStrv
['baz']
bar-keys
GStrv
['baz', 'zot']
In the generated c-code this looks as follows:
_tmp18_ = g_value_get_boxed (&property_value);
_tmp19_ = g_variant_new_strv ((gchar**) _tmp18_, -1);
Passing -1 as length to g_variant_new_strv() means the string array is considered as null terminated. Inside g_variant_new_strv() the g_strv_length() function is used to determine the length.
Hopefully it will be useful to someone else someday. :-)

Why does Dart not figure out the class instance variable in the code below

I want to understand why Dart can see that the object b in printBye() function knows it is an Instance of Bye, but it does not know how to figure out the instance variable a;
class Hello {
void world<T>(T a) {}
}
class Bye {
int a = 1;
}
class Something extends Hello {
#override
void world<T>(T a) {
printBye(a);
}
}
void printBye<T>(T b) {
print(b); // prints Instance of Bye
print(b.a); // error
}
void main() {
new Something()..world(new Bye());
}
https://dartpad.dartlang.org/527e6692846bc018f929db7aea1af583
Edit: here's a simplified version of the code that achieves the same effect:
class Bye {
int a = 1;
}
void printBye<T>(T b) {
print(b); // prints Instance of Bye
print(b.a); // error
}
void main() {
printBye(new Bye());
}
Here's a simple way to look at it: you did call printBye with a Bye, but you could have called it with any other type. When you call printBye with an int, that int wont have a .a. Therefore, you have to assume that printBye could be called with anything. Object represents that anything as every class derives from it.
If you are sure that it will be called with a Bye or a subclass, you can do this to get rid of the error:
class Bye {
int a = 1;
}
void printBye<T extends Bye>(T b) {
print(b); // prints Instance of Bye
print(b.a); // not an error anymore
}
void main() {
printBye(new Bye());
}
More info: https://dart.dev/guides/language/language-tour#restricting-the-parameterized-type

dependency injection in Arduino

I've started working with Arduino and I want to do a time share system so I do not use the delay command.
I have a problem when I try to register objects that inherit from another.
Here I have a test code that should show in the terminal: "Wow wow Miuau miuau ..."
I have doubts when I try to create an Interface and how do I declare the register () function so that Cat and Dog objects can be entered in the Animal type Array.
The following code is only to show the problem:
class Animal {
public:
void message() {
}
};
class Dog : public Animal {
public:
void message() {
Serial.println("Guau guau");
}
};
class Cat : public Animal {
public:
void message() {
Serial.println("Miau miau ");
}
};
class Multiplex {
private:
int index = 0;
Animal objects[5];
public:
void register(Animal object) {
objects[index] = object;
index++;
}
void go() {
for(int i = 0;i<index;i++) {
objects[i].message();
}
}
};
Dog dog;
Cat cat;
Multiplex multiplex;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
multiplex.register(dog);
multiplex.register(cat);
}
void loop() {
// put your main code here, to run repeatedly:
multiplex.go();
delay(1000);
}
Any help is welcome ...
Thanks and sorry for my english.
In this case you have to use polymorphism (virtual methods). But it still won't work with so many copies of "registered" object into the Animal base class (it shows nothing because Animal::message() is called). You have to use pointers (or references - but it's not so easy in this case)
class Animal { // pure virtual class (abstract class)
public:
virtual void message() = 0; // The '= 0;' makes whole class "pure virtual"
};
class Dog : public Animal {
public:
virtual void message() {
Serial.println("Guau guau");
}
};
class Cat : public Animal {
public:
virtual void message() {
Serial.println("Miau miau ");
}
};
class Multiplex {
private:
int index = 0;
Animal * objects[5];
public:
void reg(Animal * object) { // pass pointer to the object
objects[index] = object; // object must be valid for whole time
index++;
}
void go() {
for(int i = 0;i<index;i++) {
objects[i]->message();
}
}
};
Dog dog;
Cat cat;
Multiplex multiplex;
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
multiplex.reg(&dog);
multiplex.reg(&cat);
}
void loop() {
// put your main code here, to run repeatedly:
multiplex.go();
delay(1000);
}
If you don't like dynamic polymorphism, you have to use something like object type, switch and typecasting to its correct type.

How to compile an XBlockExpression within a longer generated code

I have a DSL that includes blocks that need to be wrapped as methods returned inside an anonymous class created by the generated code. For example:
model {
task {
val x = 2*5;
Math.pow(2, x)
}
}
should compile to (note task becoming an instance of Runnable, with the body of the task becoming the body of the Runnable.run() method):
import java.util.Collection;
#SuppressWarnings("all")
public class MyFile {
public Collection<Runnable> tasks() {
ArrayList<Runnable> tasks = new ArrayList<>();
tasks.add(getTask0());
return tasks;
}
public static Runnable getTask0() {
Runnable _runnable = new Runnable() {
public void run() {
final int x = (2 * 5);
Math.pow(2, x);
}
}
return _runnable;
}
}
Following the discussion in this question, I was able to get this particular example to work. (Github repo includes unit tests.) But I had to do it by representing the Task element in the grammar as a sequence of XExpressions (source), which my XbaseCompiler subclass had to iterate over (source).
Instead, it would have been nice to be able to just have Task contain an XBlockExpression in a property action, and then in the compiler just do doInternalToJavaStatement(expr.action, it, isReferenced). My sense is that this is really the "right" solution in my case, but when I tried it, this would result in an empty body of the generated run method, as if the block was not processed at all. What's going on, and am I missing some required bits of setup/wiring things together/bindings that are necessary for this to work?
you ususally try to avoid that by using a better inference strategy e.g.
Grammar
Model:
{Model}"model" "{"
vars+=Variable*
tasks+=Task*
"}"
;
Variable:
"var" name=ID ":" type=JvmParameterizedTypeReference
;
Task:
{Task} "task" content=XBlockExpression
;
Inferrer
class MyDslJvmModelInferrer extends AbstractModelInferrer {
#Inject extension JvmTypesBuilder
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(element.toClass("test.Model2")) [
for (v : element.vars) {
members+=v.toField(v.name, v.type.cloneWithProxies) [
]
}
var i = 0;
for (t : element.tasks) {
val doRunName = "doRun"+i
members += t.toMethod("task"+i, Runnable.typeRef()) [
body = '''
return new «Runnable» () {
public void run() {
«doRunName»();
}
};
'''
]
members += t.toMethod(doRunName, Void.TYPE.typeRef()) [
body = t.content
]
i = i + 1
}
]
}
}
and that basically is it.
you may follow https://bugs.eclipse.org/bugs/show_bug.cgi?id=481992
If you really want to adapt the xbase typesystem that may be a lot more of work e.g. (just covering a minimal case)
Grammar
Model:
{Model}"model" "{"
vars+=Variable*
tasks+=Task*
"}"
;
Variable:
"var" name=ID ":" type=JvmParameterizedTypeReference
;
Task:
{Task} "task" content=XTaskContent
;
XTaskContent returns xbase::XExpression:
{XTaskContent} block=XBlockExpression
;
Inferrer
class MyDslJvmModelInferrer extends AbstractModelInferrer {
#Inject extension JvmTypesBuilder
def dispatch void infer(Model element, IJvmDeclaredTypeAcceptor acceptor, boolean isPreIndexingPhase) {
acceptor.accept(element.toClass("test.Model")) [
for (v : element.vars) {
members+=v.toField(v.name, v.type.cloneWithProxies) [
]
}
var i = 0;
for (t : element.tasks) {
members += t.toMethod("task"+i, Runnable.typeRef()) [
body = t.content
]
i = i + 1
}
]
}
}
Type Computer
class MyDslTypeComputer extends XbaseTypeComputer {
override computeTypes(XExpression expression, ITypeComputationState state) {
if (expression instanceof XTaskContent) {
_computeTypes(expression as XTaskContent, state);
} else {
super.computeTypes(expression, state)
}
}
protected def void _computeTypes(XTaskContent object, ITypeComputationState state) {
state.withExpectation(getPrimitiveVoid(state)).computeTypes(object.block)
state.acceptActualType(getTypeForName(Runnable, state), ConformanceFlags.CHECKED_SUCCESS )
}
}
Compiler
class MyDslCompiler extends XbaseCompiler {
override protected internalToConvertedExpression(XExpression obj, ITreeAppendable appendable) {
if (obj instanceof XTaskContent) {
appendable.append("new ").append(Runnable).append("() {").newLine
appendable.increaseIndentation
appendable.append("public void run()").newLine
reassignThisInClosure(appendable, null)
internalToJavaStatement(obj.block, appendable, false)
appendable.newLine
appendable.decreaseIndentation
appendable.newLine.append("}")
} else {
super.internalToConvertedExpression(obj, appendable)
}
}
}
Bindings
class MyDslRuntimeModule extends AbstractMyDslRuntimeModule {
def Class<? extends ITypeComputer> bindITypeComputer() {
return MyDslTypeComputer
}
def Class<? extends XbaseCompiler> bindXbaseCompiler() {
return MyDslCompiler
}
}

Resources