-
Notifications
You must be signed in to change notification settings - Fork 7
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Filter functions, extern vars, defines and unused types from included headers #113
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Made a first pass. It looks like it is possible to simplify a lot of stuff and even get rid of LocationManager
in favour of having more details in each Location
instance and moving filtering to the generator (llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir)
) where I feel it belongs.
bindgen/visitor/TreeVisitor.cpp
Outdated
@@ -69,8 +71,8 @@ bool TreeVisitor::VisitEnumDecl(clang::EnumDecl *enumdecl) { | |||
std::string scalaType = typeTranslator.getTypeFromTypeMap( | |||
enumdecl->getIntegerType().getUnqualifiedType().getAsString()); | |||
|
|||
std::shared_ptr<Type> alias = | |||
ir.addEnum(name, scalaType, std::move(enumerators)); | |||
std::shared_ptr<Type> alias = ir.addEnum( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused assignment
bindgen/visitor/TreeVisitor.cpp
Outdated
@@ -1,10 +1,12 @@ | |||
#include "TreeVisitor.h" | |||
|
|||
HeaderManager headerMan; | |||
|
|||
std::set<std::string> locations; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks like this is no longer used and can be removed.
bindgen/ir/Enum.cpp
Outdated
assert(!isAnonymous()); | ||
return std::make_shared<TypeDef>("enum_" + name, shared_from_this()); | ||
return std::make_shared<TypeDef>("enum_" + name, shared_from_this(), | ||
std::move(location)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand why the enum
doesn't have a location
itself, which can be "reused" here.
Also, from TypeDef::location
doc string:
nullptr
if type is located in main file or is generated.
this is generated, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sorry, docstring is wrong, location
is null only if it is generated
bindgen/ir/IR.cpp
Outdated
return typeDefs.back(); | ||
} | ||
return nullptr; | ||
} | ||
|
||
void IR::addStruct(std::string name, std::vector<Field *> fields, | ||
uint64_t typeSize) { | ||
uint64_t typeSize, std::shared_ptr<Location> location) { | ||
std::shared_ptr<Struct> s = | ||
std::make_shared<Struct>(name, std::move(fields), typeSize); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Again, I'm curious why the location is associated with the generated typedef instead of the "concrete" type.
The latter would require fewer changes, e.g. no need for TypeDef::setLocation()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TypeDef
instance in any case should have location
because it may reference any type: typedef int size
.
Struct
, Union
and Enum
are not referenced directly, corresponding TypeDef
is generated for each instance, so it is okay to use location
from TypeDef
.
It is possible to add location
to them too, but in some sense TypeDef
replaces actual type, and we store Struct
, .. only for helper methods.
So when generator checks for unused external types it can go through all typedefs and check their location
.
If a TypeDef
is removed and it references a struct, the struct is also removed.
I am not sure if it was right choice, I can try to add location
to Struct
etc and see if it will make code more complicated.
@@ -12,14 +12,15 @@ | |||
*/ | |||
class ScalaFrontendAction : public clang::ASTFrontendAction { | |||
public: | |||
explicit ScalaFrontendAction(IR &ir); | |||
ScalaFrontendAction(IR &ir, LocationManager &locationManager); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LocationManager
is declared in ir/location
so it makes sense to add it as a member to IR to avoid passing it where IR
is passed, etc. Better yet might be to have Location
under ir/
but have the LocationManager
be part of the TreeVisitor
so it has access to the SourceManager
. We don't need the manager once we are done with the AST because we have the locations themselves.
: mainHeaderPath(std::move(mainHeaderPath)) {} | ||
|
||
void LocationManager::loadConfig(const std::string &path) { | ||
// TODO: implement |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will this use the stdHeader.config
file?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
@@ -100,6 +104,9 @@ void DefineFinder::MacroUndefined(const clang::Token ¯oNameTok, | |||
const clang::MacroDefinition &md, | |||
const clang::MacroDirective *undef) { | |||
clang::SourceManager &sm = compiler.getSourceManager(); | |||
if (!sm.isInMainFile(undef->getLocation())) { | |||
return; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Having a test for this would be very valuable.
bindgen/ir/location/Location.h
Outdated
class Location { | ||
public: | ||
virtual ~Location() = default; | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it would be better to have a single Location
class with the include file path, isInMainFile
and position in the file for error reporting etc. It sounds like you are considering that. If we put the position there it would also render much (or all) of the LocationManager
obsolete because the TreeVisitor
will just generate a new Location
every time. The mapping from file path to Scala module path can then be done in the generator.
|
||
std::shared_ptr<Location> | ||
LocationManager::getLocation(std::string pathToHeader, | ||
std::string includeLocation) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's the purpose of includeLocation
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pathToHeader
minus includeLocation
will give us relative path to header (the path that is used in include
for example bits/stdio.h
).
stdHeader file should contain these relative paths (not only header names) so we will be able to correctly map headers to existing bindings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh no includeLocation
is not an include path
bindgen/ir/IR.cpp
Outdated
@@ -353,3 +365,47 @@ IR::~IR() { | |||
variables.clear(); | |||
varDefines.clear(); | |||
} | |||
|
|||
void IR::removeUnusedExternalTypes() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think it makes sense to remove types, since we loose a lot of information. We need the external types to correctly reference types from other modules, like stdio.FILE
. It would be better to update the generators to skip when !isInMainFile
and then have them also prefix the module path when referencing an external type.
Not ready for review |
f2e29e6
to
5447079
Compare
bindgen/Main.cpp
Outdated
} | ||
|
||
locations.clear(); | ||
assert(op.getSourcePathList().size() == 1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it possible to lift this requirement? If it is not possible at this point, it would be good to exit with a proper error message.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I will lift the requirement and add proper error message
@@ -102,7 +102,7 @@ TypeTranslator::translateStructOrUnionOrEnum(const clang::QualType &qtpe) { | |||
/* type is not yet defined. | |||
* TypeDef with nullptr will be created. | |||
* nullptr will be replaced by actual type when the type is declared. */ | |||
typeDef = ir.addTypeDef(nameWithoutSpace, nullptr); | |||
typeDef = ir.addTypeDef(nameWithoutSpace, nullptr, nullptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually passing a location here would allow us to provide a better diagnostic if an opaque type is used in a problematic way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a good idea but we should not use location
field for this.
Maybe create an optional field typeDeclarationLocation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I started doing it but it required passing Location
instance to methods of TypeTranslator
and it does not look good to me, so I decided to leave it for now.
I hope that after fixing #106 we will not see the error message often (except the case when one wants to generated bindings for broken header).
bindgen/ir/IR.cpp
Outdated
@@ -171,18 +179,19 @@ void IR::generate(const std::string &excludePrefix) { | |||
if (!generated) { | |||
setScalaNames(); | |||
filterDeclarations(excludePrefix); | |||
// removeUnusedExternalTypedefs(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove commented out code.
bindgen/ir/IR.cpp
Outdated
} | ||
|
||
template <typename T> | ||
bool IR::isOutputted(const std::shared_ptr<T> &type) const { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found the name a bit confusing, maybe shouldGenerate
or shouldOutput
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@@ -118,7 +128,7 @@ bool Struct::hasHelperMethods() const { | |||
return !fields.empty() && fields.size() < SCALA_NATIVE_MAX_STRUCT_FIELDS; | |||
} | |||
|
|||
std::string Struct::getAliasType() const { return "struct_" + name; } | |||
std::string Struct::getTypeAlias() const { return "struct_" + name; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
bindgen/ir/Struct.cpp
Outdated
@@ -176,3 +196,11 @@ std::string Union::generateHelperClass() const { | |||
} | |||
|
|||
std::string Union::getTypeAlias() const { return "union_" + name; } | |||
|
|||
bool Union::operator==(const Type &other) const { | |||
auto *structOrUnion = dynamic_cast<const StructOrUnion *>(&other); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not cast to Union?
4cdb3d5
to
cb62f50
Compare
Cast type to Union/Struct in operator== of Union/Struct class Fix error message when definition of opaque type was not found
cb62f50
to
7e45389
Compare
Closes #13
Ignore functions, extern variables and defines from included headers.
Removed
HeaderManager
, addedLocationManager
that creates instances ofLocation
for eachTypeDef
.Location
has 2 subclasses:ScalaLocation
means that type is defined in another scala object (not supported yet)SourceLocation
indicates that type is defined in main header or in included headerIf type is defined in included header and it is not used then it is removed.
Now I think that
ScalaLocation
is a bad idea because it does not prevent creation ofStruct
,Union
etc andTypeDef
instances.So it would be better to create an
ImportedType
instead ofTypeDef
withScalaLocation
.TODO: