Skip to content

Commit

Permalink
Merge pull request #233 from nsakabe-fixstars/test_headercvt
Browse files Browse the repository at this point in the history
Test headercvt's functionality
  • Loading branch information
LWisteria authored Sep 11, 2019
2 parents 9542f46 + 2aab46d commit 77b30d8
Show file tree
Hide file tree
Showing 5 changed files with 378 additions and 38 deletions.
113 changes: 75 additions & 38 deletions headercvt/headercvt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,38 @@

namespace headercvt{

class MarkableLLVMOsOstream{
llvm::raw_os_ostream llvm_ost;
bool used = false;
public:
MarkableLLVMOsOstream(std::ofstream& ofstream):llvm_ost(ofstream){
}
template <typename T>
MarkableLLVMOsOstream& operator << (T&& rhs){
llvm_ost << std::forward<T>(rhs);
used = true;
return *this;
}
decltype(llvm_ost)& without_using(){
return llvm_ost;
}
void use(){
used = true;
}
bool vacant() const{
return !used;
}
void flush(){
llvm_ost.flush();
}
};

std::ofstream
types("types.pxi"),
func_decl("func_decl.pxi"),
preprocessor_defines("preprocessor_defines.pxi"),
not_handled("not_handled.txt");
llvm::raw_os_ostream
MarkableLLVMOsOstream
types_ostream(types),
func_decl_ostream(func_decl),
preprocessor_defines_ostream(preprocessor_defines),
Expand Down Expand Up @@ -56,17 +82,17 @@ static std::string clean_type_string(clang::QualType const& type){
class preprocessor_defines_extractor : public clang::PPCallbacks{
private:
unsigned Indentation;
llvm::raw_ostream& Out;
MarkableLLVMOsOstream& Out;

llvm::raw_ostream& Indent() { return Indent(Indentation); }
llvm::raw_ostream& Indent(unsigned Indentation) {
MarkableLLVMOsOstream& Indent() { return Indent(Indentation); }
MarkableLLVMOsOstream& Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << indent_str;
return Out;
}

public:
preprocessor_defines_extractor(llvm::raw_ostream& Out): Out(Out){
preprocessor_defines_extractor(MarkableLLVMOsOstream& Out): Out(Out){
Indentation = preprocessor_defines_indentation;
}

Expand Down Expand Up @@ -148,30 +174,30 @@ class simple_vardecl_printer : public clang::DeclVisitor<simple_vardecl_printer>


class typedef_printer : public clang::DeclVisitor<typedef_printer>{
llvm::raw_ostream &Out;
MarkableLLVMOsOstream &Out;
clang::PrintingPolicy Policy;
unsigned Indentation;

llvm::raw_ostream& Indent() { return Indent(Indentation); }
llvm::raw_ostream& Indent(unsigned Indentation) {
MarkableLLVMOsOstream& Indent() { return Indent(Indentation); }
MarkableLLVMOsOstream& Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << indent_str;
return Out;
}
public:
typedef_printer(llvm::raw_ostream &Out, const clang::PrintingPolicy &Policy,
typedef_printer(MarkableLLVMOsOstream &Out, const clang::PrintingPolicy &Policy,
const clang::ASTContext &, unsigned Indentation = 0)
: Out(Out), Policy(Policy), Indentation(Indentation) {}


void VisitTypedefDecl(clang::TypedefDecl* D) {
if (D->getTypeSourceInfo()->getType().getTypePtr()->isUnionType()){
Out << "# union reference ignored\n";
Out.without_using() << "# union reference ignored\n";
return;
}

if (D->getTypeSourceInfo()->getType()->isFunctionPointerType()){
Out << "# function pointer ignored\n";
Out.without_using() << "# function pointer ignored\n";
return;
}

Expand All @@ -192,12 +218,12 @@ class typedef_printer : public clang::DeclVisitor<typedef_printer>{

void VisitRecordDecl(clang::RecordDecl *D) {
if (D->isUnion()) {
Out << "# union declaration(" << D->getName() << ") ignored\n";
Out.without_using() << "# union declaration(" << D->getName() << ") ignored\n";
return;
}
const std::regex pthread_detector(R"(.*pthread.*)");
if(std::regex_match(D->getNameAsString(), pthread_detector)) {
Out << "# pthread-related type ignored\n";
Out.without_using() << "# pthread-related type ignored\n";
return;
}

Expand Down Expand Up @@ -227,19 +253,19 @@ class typedef_printer : public clang::DeclVisitor<typedef_printer>{


class grouped_typedef_struct_printer : public clang::DeclVisitor<grouped_typedef_struct_printer>{
llvm::raw_ostream &Out;
MarkableLLVMOsOstream &Out;
clang::PrintingPolicy Policy;
unsigned Indentation;

llvm::raw_ostream& Indent() { return Indent(Indentation); }
llvm::raw_ostream& Indent(unsigned Indentation) {
MarkableLLVMOsOstream& Indent() { return Indent(Indentation); }
MarkableLLVMOsOstream& Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << indent_str;
return Out;
}

public:
grouped_typedef_struct_printer(llvm::raw_ostream &Out, const clang::PrintingPolicy &Policy,
grouped_typedef_struct_printer(MarkableLLVMOsOstream &Out, const clang::PrintingPolicy &Policy,
const clang::ASTContext &, unsigned Indentation = 0)
: Out(Out), Policy(Policy), Indentation(Indentation) {
}
Expand All @@ -248,7 +274,7 @@ class grouped_typedef_struct_printer : public clang::DeclVisitor<grouped_typedef
const std::regex pthread_detector(R"(.*pthread.*)");
if(std::regex_match(RD->getNameAsString(), pthread_detector)
|| std::regex_match(TDD->getNameAsString(), pthread_detector)) {
Out << "# pthread-related type ignored\n";
Out.without_using() << "# pthread-related type ignored\n";
return;
}

Expand Down Expand Up @@ -300,20 +326,20 @@ class grouped_typedef_struct_printer : public clang::DeclVisitor<grouped_typedef
};

class funcdecl_printer : public clang::DeclVisitor<funcdecl_printer>{
llvm::raw_ostream &Out;
MarkableLLVMOsOstream &Out;
clang::PrintingPolicy Policy;
const clang::ASTContext &Context;
unsigned Indentation;

llvm::raw_ostream& Indent() { return Indent(Indentation); }
llvm::raw_ostream& Indent(unsigned Indentation) {
MarkableLLVMOsOstream& Indent() { return Indent(Indentation); }
MarkableLLVMOsOstream& Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << indent_str;
return Out;
}

public:
funcdecl_printer(llvm::raw_ostream &Out, const clang::PrintingPolicy &Policy,
funcdecl_printer(MarkableLLVMOsOstream &Out, const clang::PrintingPolicy &Policy,
const clang::ASTContext &Context, unsigned Indentation = 0)
: Out(Out), Policy(Policy), Context(Context), Indentation(Indentation) {}

Expand Down Expand Up @@ -364,11 +390,12 @@ class funcdecl_printer : public clang::DeclVisitor<funcdecl_printer>{
Proto += ")";


AFT->getReturnType().print(Out, Policy, Proto);
AFT->getReturnType().print(Out.without_using(), Policy, Proto);
Proto.clear();
Out << Proto;
} else {
Ty.print(Out, Policy, Proto);
Ty.print(Out.without_using(), Policy, Proto);
Out.use();
}

Out << "\n";
Expand All @@ -378,20 +405,20 @@ class funcdecl_printer : public clang::DeclVisitor<funcdecl_printer>{


class general_decl_visitor : public clang::DeclVisitor<general_decl_visitor>{
llvm::raw_ostream &Out;
MarkableLLVMOsOstream &Out;
clang::PrintingPolicy Policy;
const clang::ASTContext &Context;
unsigned Indentation;

llvm::raw_ostream& Indent() { return Indent(Indentation); }
llvm::raw_ostream& Indent(unsigned Indentation) {
MarkableLLVMOsOstream& Indent() { return Indent(Indentation); }
MarkableLLVMOsOstream& Indent(unsigned Indentation) {
for (unsigned i = 0; i != Indentation; ++i)
Out << indent_str;
return Out;
}

public:
general_decl_visitor(llvm::raw_ostream &Out, const clang::PrintingPolicy &Policy,
general_decl_visitor(MarkableLLVMOsOstream &Out, const clang::PrintingPolicy &Policy,
const clang::ASTContext &Context, unsigned Indentation = 0)
: Out(Out), Policy(Policy), Context(Context), Indentation(Indentation) { }

Expand Down Expand Up @@ -453,13 +480,11 @@ class general_decl_visitor : public clang::DeclVisitor<general_decl_visitor>{
if (clang::isa<clang::FunctionDecl>(*D)){
funcdecl_printer FuncDeclPrinter(func_decl_ostream, Policy, Context, func_decl_indentation);
FuncDeclPrinter.Visit(clang::cast<clang::FunctionDecl>(*D));
func_decl_ostream.flush();
}

if (clang::isa<clang::TypedefDecl>(*D) || clang::isa<clang::RecordDecl>(*D)){
typedef_printer TypedefPrinter(types_ostream, Policy, Context, types_indentation);
TypedefPrinter.Visit(*D);
types_ostream.flush();
}

} // end of in-declcontext iteration
Expand All @@ -473,12 +498,11 @@ class general_decl_visitor : public clang::DeclVisitor<general_decl_visitor>{

void ProcessDeclGroup(clang::SmallVectorImpl<clang::Decl*>& Decls) {
this->Indent();
llvm::raw_os_ostream declgroup_ostream(types);
processTypedefStructDeclGroup(Decls.data(), Decls.size(), declgroup_ostream);
processTypedefStructDeclGroup(Decls.data(), Decls.size(), types_ostream);
Decls.clear();
}

void processTypedefStructDeclGroup(clang::Decl** Begin, unsigned NumDecls, llvm::raw_ostream &Out) {
void processTypedefStructDeclGroup(clang::Decl** Begin, unsigned NumDecls, MarkableLLVMOsOstream &Out) {
if(NumDecls == 1) return;

clang::TagDecl* TD = clang::dyn_cast<clang::TagDecl>(*Begin);
Expand Down Expand Up @@ -512,7 +536,7 @@ class general_decl_visitor : public clang::DeclVisitor<general_decl_visitor>{
return;
}
case clang::TagTypeKind::TTK_Union :
Out << "# union declaration ignored\n";
Out.without_using() << "# union declaration ignored\n";
return;
default:
return;
Expand Down Expand Up @@ -565,20 +589,33 @@ int main(int argc, const char** argv){
// setup files and their indentations
using namespace headercvt;

preprocessor_defines_ostream << "cdef extern from \"CL/cl.h\":\n";
preprocessor_defines_ostream.without_using() << "cdef extern from \"CL/cl.h\":\n";
preprocessor_defines_indentation ++;
preprocessor_defines_ostream << indent_str << "cdef enum:\n";
preprocessor_defines_ostream.without_using() << indent_str << "cdef enum:\n";
preprocessor_defines_indentation ++;

func_decl_ostream << "cdef extern from \"CL/cl.h\":\n";
func_decl_ostream.without_using() << "cdef extern from \"CL/cl.h\":\n";
func_decl_indentation ++;

types_ostream << "cdef extern from \"CL/cl.h\":\n";
types_ostream.without_using() << "cdef extern from \"CL/cl.h\":\n";
types_indentation ++;
}

auto const result_value = tool.run(clang::tooling::newFrontendActionFactory<headercvt::ast_frontend_action>().get());

{
using namespace headercvt;
if (preprocessor_defines_ostream.vacant()){
preprocessor_defines_ostream << indent_str << indent_str << "pass\n";
}
if (func_decl_ostream.vacant()){
func_decl_ostream << indent_str << "pass\n";
}
if (types_ostream.vacant()){
types_ostream << indent_str << "pass\n";
}
}

headercvt::func_decl_ostream.flush();
headercvt::types_ostream.flush();
headercvt::not_handled_ostream.flush();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import locale
import os
import subprocess
import tempfile


headercvt_abspath = os.path.join(
os.path.dirname(__file__),
"..", # opencl_tests
"..", # clpy_tests
"..", # tests
"..", # clpy
"headercvt",
"headercvt")


def check_existence_of_headercvt():
if not os.path.isfile(headercvt_abspath):
raise FileNotFoundError("headercvt does not exist")


def exec_headercvt(workingdir, source):
subprocess.run(
[headercvt_abspath, "/dev/stdin", "--"],
cwd=workingdir,
input=source.encode(locale.getpreferredencoding()),
timeout=1,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
check=True
)


def get_result_files(workingdir):
with open(os.path.join(workingdir, "func_decl.pxi"), "r") as f:
func_decl_str = f.read()
with open(os.path.join(workingdir, "preprocessor_defines.pxi"), "r") as f:
preprocessor_defines_str = f.read()
with open(os.path.join(workingdir, "types.pxi"), "r") as f:
types_str = f.read()
return {
"func_decl": func_decl_str,
"preprocessor_defines": preprocessor_defines_str,
"types": types_str
}


def kick_headercvt_and_get_results(workingdir, source):
exec_headercvt(workingdir, source)
return get_result_files(workingdir)


def contains(result_string, match_string):
return match_string in result_string


def compile_with(workingdir, source):
source = """
include "func_decl.pxi"
include "preprocessor_defines.pxi"
include "types.pxi"
""" + source

with open(os.path.join(workingdir, "test_case.pyx"), "w") as f:
f.write(source)
f.flush()
os.fsync(f.fileno())
try:
subprocess.run(
["cython", f.name],
cwd=workingdir,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
check=True)
return True
except subprocess.CalledProcessError as e:
print(e.stdout.decode(locale.getpreferredencoding()))
print(e.stderr.decode(locale.getpreferredencoding()))
return False


def with_temp_wd(function):
def impl(self):
with tempfile.TemporaryDirectory() as wd:
function(self, wd=wd)
return impl
Loading

0 comments on commit 77b30d8

Please sign in to comment.