コード例 #1
0
ファイル: ASTConsumer.cpp プロジェクト: Celtoys/clReflect
void ASTConsumer::AddMethodDecl(clang::NamedDecl* decl, const std::string& name, const std::string& parent_name)
{
	// Cast to a method
	clang::CXXMethodDecl* method_decl = llvm::dyn_cast<clang::CXXMethodDecl>(decl);
	assert(method_decl != 0 && "Failed to cast to C++ method declaration");

	// Ignore overloaded operators for now
	if (method_decl->isOverloadedOperator())
		return;

	std::vector<cldb::Field> parameters;
	if (method_decl->isInstance())
	{
		// Parse the 'this' type, treating it as the first parameter to the method
		cldb::Field this_param;
		Status status = MakeField(*this, method_decl->getThisType(m_ASTContext), "this", name, 0, this_param, MF_CHECK_TYPE_IS_REFLECTED);
		if (status.HasWarnings())
		{
			status.Print(method_decl->getLocation(), m_ASTContext.getSourceManager(), va("Failed to reflect method '%s' due to invalid 'this' type", name.c_str()));
			return;
		}
		parameters.push_back(this_param);
	}

	// Parse and add the method
	MakeFunction(decl, name, parent_name, parameters);
}
コード例 #2
0
ファイル: ASTConsumer.cpp プロジェクト: Celtoys/clReflect
void ASTConsumer::AddFieldDecl(clang::NamedDecl* decl, const std::string& name, const std::string& parent_name, const clang::ASTRecordLayout* layout)
{
	// Cast to a field
	clang::FieldDecl* field_decl = llvm::dyn_cast<clang::FieldDecl>(decl);
	assert(field_decl != 0 && "Failed to cast to field declaration");

	// These are implicitly generated by clang so skip them
	if (field_decl->isAnonymousStructOrUnion())
		return;

	// Parse and add the field
	cldb::Field field;
	cldb::u32 offset = layout->getFieldOffset(field_decl->getFieldIndex()) / 8;
	std::string field_name = field_decl->getName().str();
	Status status = MakeField(*this, field_decl->getType(), field_name.c_str(), parent_name, offset, field, MF_CHECK_TYPE_IS_REFLECTED);
	if (status.HasWarnings())
	{
		status.Print(field_decl->getLocation(), m_ASTContext.getSourceManager(), va("Failed to reflect field in '%s'", parent_name.c_str()));
		return;
	}

	LOG(ast, INFO, "Field: %s%s%s %s\n",
		field.qualifier.is_const ? "const " : "",
		field.type.text.c_str(),
		field.qualifier.op == cldb::Qualifier::POINTER ? "*" : field.qualifier.op == cldb::Qualifier::REFERENCE ? "&" : "",
		field.name.text.c_str());
	m_DB.AddPrimitive(field);
}
コード例 #3
0
ファイル: ASTConsumer.cpp プロジェクト: Celtoys/clReflect
void ASTConsumer::MakeFunction(clang::NamedDecl* decl, const std::string& function_name, const std::string& parent_name, std::vector<cldb::Field>& parameters)
{
	// Cast to a function
	clang::FunctionDecl* function_decl = llvm::dyn_cast<clang::FunctionDecl>(decl);
	assert(function_decl != 0 && "Failed to cast to function declaration");

	// Only add the function once
	if (!function_decl->isFirstDeclaration())
		return;

	// Parse the return type - named as a reserved keyword so it won't clash with user symbols
	cldb::Field return_parameter;
	Status status = MakeField(*this, function_decl->getResultType(), "return", function_name, -1, return_parameter, 0);
	if (status.HasWarnings())
	{
		status.Print(function_decl->getLocation(), m_ASTContext.getSourceManager(), va("Failed to reflect function '%s' due to invalid return type", function_name.c_str()));
		return;
	}

	// Try to gather every parameter successfully before adding the function
	int index = parameters.size();
	for (clang::FunctionDecl::param_iterator i = function_decl->param_begin(); i != function_decl->param_end(); ++i)
	{
		clang::ParmVarDecl* param_decl = *i;

		// Check for unnamed parameters
		llvm::StringRef param_name = param_decl->getName();
		if (param_name.empty())
		{
			Status().Print(function_decl->getLocation(), m_ASTContext.getSourceManager(), va("Unnamed function parameters not supported - skipping reflection of '%s'", function_name.c_str()));
			return;
		}

		// Collect a list of constructed parameters in case evaluating one of them fails
		cldb::Field parameter;
		std::string param_name_str = param_name.str();
		status = MakeField(*this, param_decl->getType(), param_name_str.c_str(), function_name, index++, parameter, 0);
		if (status.HasWarnings())
		{
			status.Print(function_decl->getLocation(), m_ASTContext.getSourceManager(), va("Failed to reflection function '%s'", function_name.c_str()));
			return;
		}
		parameters.push_back(parameter);
	}

	// Generate a hash unique to this function among other functions of the same name
	// This is so that its parameters can re-parent themselves correctly
	cldb::u32 unique_id = cldb::CalculateFunctionUniqueID(parameters);

	// Parent each parameter to the function
	return_parameter.parent_unique_id = unique_id;
	for (size_t i = 0; i < parameters.size(); i++)
		parameters[i].parent_unique_id = unique_id;

	// Add the function
	LOG(ast, INFO, "function %s\n", function_name.c_str());
	m_DB.AddPrimitive(cldb::Function(
		m_DB.GetName(function_name.c_str()),
		m_DB.GetName(parent_name.c_str()),
		unique_id));

	LOG_PUSH_INDENT(ast);

	// Only add the return parameter if it's non-void
	if (return_parameter.type.text != "void")
	{
		LOG(ast, INFO, "Returns: %s%s%s\n",
			return_parameter.qualifier.is_const ? "const " : "",
			return_parameter.type.text.c_str(),
			return_parameter.qualifier.op == cldb::Qualifier::POINTER ? "*" : return_parameter.qualifier.op == cldb::Qualifier::REFERENCE ? "&" : "");
		m_DB.AddPrimitive(return_parameter);
	}
	else
	{
		LOG(ast, INFO, "Returns: void (not added)\n");
	}

	// Add the parameters
	for (std::vector<cldb::Field>::iterator i = parameters.begin(); i != parameters.end(); ++i)
	{
		LOG(ast, INFO, "%s%s%s %s\n",
			i->qualifier.is_const ? "const " : "",
			i->type.text.c_str(),
			i->qualifier.op == cldb::Qualifier::POINTER ? "*" : i->qualifier.op == cldb::Qualifier::REFERENCE ? "&" : "",
			i->name.text.c_str());
		m_DB.AddPrimitive(*i);
	}

	LOG_POP_INDENT(ast);
}
コード例 #4
0
ファイル: ASTConsumer.cpp プロジェクト: Celtoys/clReflect
void ASTConsumer::AddClassDecl(clang::NamedDecl* decl, const std::string& name, const std::string& parent_name)
{
	// Cast to a record (NOTE: CXXRecord is a temporary clang type and will change in future revisions)
	clang::CXXRecordDecl* record_decl = llvm::dyn_cast<clang::CXXRecordDecl>(decl);
	assert(record_decl != 0 && "Failed to cast to record declaration");

	// Check for forward-declared types
	bool forward_decl = false;
	if (record_decl->isThisDeclarationADefinition() == clang::VarDecl::DeclarationOnly)
	{
		//
		// This classification of CXXRecord also comes through the AST like so:
		//
		//    namespace ns
		//    {
		//        class ClassName { };
		//    }
		//
		//    CXXRecord ns::ClassName
		//       CXXRecord ns::ClassName::ClassName
		//       CXXConstructor ns::ClassName::ClassName
		//
		// So before every constructor of a class, there's a superfluous CXX declaration of the same name.
		// Not sure why it's here, however the "free standing" flag is documented in the code to mark
		// these cases:
		//
		//    namespace ns
		//    {
		//       class ClassName;
		//    }
		//
		//    CXXRecord ns::ClassName
		//
		// And these are the exact cases that represent a reflected forward-declaration!
		//

		if (!record_decl->isFreeStanding())
			return;
		forward_decl = true;
	}

	// Ignore classes with virtual bases
	if (!forward_decl && record_decl->getNumVBases())
	{
		Status().Print(record_decl->getLocation(), m_ASTContext.getSourceManager(), va("Class '%s' has an unsupported virtual base class", name.c_str()));
		return;
	}

	// Name gets added to the database if it's not already there
	cldb::Name type_name = m_DB.GetName(name.c_str());

	// Parse base classes
	std::vector<cldb::Name> base_names;
	if (!forward_decl && record_decl->getNumBases())
	{
		for (clang::CXXRecordDecl::base_class_const_iterator base_it = record_decl->bases_begin(); base_it != record_decl->bases_end(); base_it++)
		{
			cldb::Name base_name;
			Status status = ParseBaseClass(*this, type_name, *base_it, base_name);
			if (status.HasWarnings())
			{
				status.Print(record_decl->getLocation(), m_ASTContext.getSourceManager(), va("Failed to reflect class '%s'", name.c_str()));
				return;
			}

			// If the base class is valid, then add the inheritance relationship
			m_DB.AddTypeInheritance(type_name, base_name);
			base_names.push_back(base_name);
		}
	}

	if (record_decl->isAnonymousStructOrUnion())
	{
		// Add declarations to the parent
		const clang::ASTRecordLayout& layout = m_ASTContext.getASTRecordLayout(record_decl);
		AddContainedDecls(decl, parent_name, &layout);
	}
	else
	{
		LOG(ast, INFO, "class %s", name.c_str());

		// Ensure there's at least an empty class definition in the database for this name
		cldb::Class* class_ptr = m_DB.GetFirstPrimitive<cldb::Class>(name.c_str());
		if (class_ptr == nullptr)
		{
			bool is_class = record_decl->getTagKind() == clang::TTK_Class;
			m_DB.AddPrimitive(cldb::Class(m_DB.GetName(name.c_str()), m_DB.GetName(parent_name.c_str()), is_class));
			class_ptr = m_DB.GetFirstPrimitive<cldb::Class>(name.c_str());
		}

		if (!forward_decl)
		{
			// Fill in the missing class size
			const clang::ASTRecordLayout& layout = m_ASTContext.getASTRecordLayout(record_decl);
			class_ptr->size = layout.getSize().getQuantity();

			for (size_t i = 0; i < base_names.size(); i++)
				LOG_APPEND(ast, INFO, (i == 0) ? " : %s" : ", %s", base_names[i].text.c_str());
			LOG_NEWLINE(ast);

			// Populate class contents
			AddContainedDecls(decl, name, &layout);
		}

		else
		{
			// Forward-declaration log
			LOG_NEWLINE(ast);
		}
	}
}