diff options
author | Sergio Martins <sergio.martins@kdab.com> | 2019-06-11 22:41:54 +0100 |
---|---|---|
committer | Sergio Martins <sergio.martins@kdab.com> | 2019-06-11 22:41:54 +0100 |
commit | 5515bf1587528e8898c7d7ab17b2dd6ed0a46b9e (patch) | |
tree | 90e5ea8143247ce8c680f1cb86c50369c3f5bcb1 | |
parent | 5e226f6cf876137f2e71c9e57bd2a1e5221a64b4 (diff) |
WIP
-rw-r--r-- | .gitignore | 2 | ||||
-rwxr-xr-x | dev-scripts/miniAstDumper.py | 75 | ||||
-rw-r--r-- | src/MiniAstDumper.cpp | 83 | ||||
-rw-r--r-- | src/MiniAstDumper.h | 4 |
4 files changed, 149 insertions, 15 deletions
@@ -32,3 +32,5 @@ CPackConfig.cmake CPackSourceConfig.cmake *.yaml *.fixed +*.cbor +*.tmp diff --git a/dev-scripts/miniAstDumper.py b/dev-scripts/miniAstDumper.py index 43577659..ec80d092 100755 --- a/dev-scripts/miniAstDumper.py +++ b/dev-scripts/miniAstDumper.py @@ -2,6 +2,12 @@ import cbor, sys, time, os +ClassFlag_None = 0 +ClassFlag_QObject = 1 + +MethodFlag_None = 0 +MethodFlag_Signal = 1 + class SourceLocation: def __init__(self): self.filename = "" @@ -35,6 +41,7 @@ class Function: def __init__(self): self.id = 0 self.qualified_name = "" + self.num_called = 0 # How many times this function was called def check_sanity(self): if self.id == -1: @@ -48,7 +55,6 @@ class CXXMethod(Function): Function.__init__(self) self.method_flags = 0 - class CXXClass: def __init__(self): # self.id = -1 @@ -80,8 +86,12 @@ class GlobalAST: for f in self.function_calls: f.check_sanity() + +_check_sanity = False _globalAST = GlobalAST() _next_function_id = 1 +_function_map = {} + def next_function_id(): global _next_function_id result = _next_function_id @@ -138,15 +148,21 @@ def load_cbor(filename, globalAST): cxxclass = CXXClass() # cxxclass.id = stuff['id'] cxxclass.qualified_name = stuff['name'] + if 'class_flags' in stuff: + cxxclass.class_flags = stuff['class_flags'] if 'methods' in stuff: for m in stuff['methods']: method = CXXMethod() method.id = next_function_id() # Attribute a sequential id, that's unique across TUs + _function_map[method.id] = method method.qualified_name = m['name'] cxxclass.methods.append(method) + if 'method_flags' in m: + method.method_flags = m['method_flags'] + local_id_in_tu = m['id'] if local_id_in_tu in tu_function_map.keys(): @@ -158,6 +174,7 @@ def load_cbor(filename, globalAST): if stuff['type'] == 48: # FunctionDecl func = Function() func.id = next_function_id() # Attribute a sequential id, that's unique across TUs + _function_map[func.id] = func func.qualified_name = stuff['name'] globalAST.functions.append(func) local_id_in_tu = stuff['id'] @@ -184,6 +201,41 @@ def load_cbor(filename, globalAST): funccall.loc_start = source_loc globalAST.function_calls.append(funccall) + +def get_all_method_names(): + total_methods = [] + for c in _globalAST.cxx_classes: + for m in c.methods: + total_methods.append(m.qualified_name) + return total_methods + +def print_qobjects(ast): + for c in ast.cxx_classes: + if c.class_flags & ClassFlag_QObject: + print(c.qualified_name) + + +def calculate_call_counts(ast): + for c in ast.function_calls: + if c.callee_id in _function_map: + _function_map[c.callee_id].num_called += 1 + +def print_unused_signals(ast): + for c in ast.cxx_classes: + for m in c.methods: + if (m.method_flags & MethodFlag_Signal) and m.num_called == 0: + print("Signal " + m.qualified_name + " never called") + + + +def process_all_files(files): + for f in files: + load_cbor(f, _globalAST) + + return True + + + #def get_class_by_name(qualified_name): # result = [] # for c in _globalAST.cxx_classes: @@ -198,10 +250,18 @@ def load_cbor(filename, globalAST): # result.append(f) #return result -load_cbor(sys.argv[1], _globalAST) -print ("Functions: " + str(len(_globalAST.functions))) + +# load_cbor(sys.argv[1], _globalAST) + + +#print ("Functions: " + str(len(_globalAST.functions))) + + + +#print(str(total_methods)) + #_globalAST.check_sanity() @@ -220,3 +280,12 @@ print ("Functions: " + str(len(_globalAST.functions))) # print(c.qualified_name) #print(cborData) + + +if not process_all_files(sys.argv[1:]): + print('Error processing files') + sys.exit(1) + +calculate_call_counts(_globalAST) +print_unused_signals(_globalAST) +#print_qobjects(_globalAST) diff --git a/src/MiniAstDumper.cpp b/src/MiniAstDumper.cpp index c6ddaaf2..1f13cbed 100644 --- a/src/MiniAstDumper.cpp +++ b/src/MiniAstDumper.cpp @@ -22,9 +22,11 @@ #include "MiniAstDumper.h" #include "SourceCompatibilityHelpers.h" +#include "AccessSpecifierManager.h" #include "clazy_stl.h" -#include "StringUtils.h" +#include "FunctionUtils.h" #include "QtUtils.h" +#include "StringUtils.h" #include <clang/Frontend/CompilerInstance.h> #include <clang/Frontend/FrontendPluginRegistry.h> @@ -35,6 +37,15 @@ using namespace clang; using namespace std; +enum ClassFlag { + ClassFlag_None = 0, + ClassFlag_QObject = 1 +}; + +enum MethodFlag { + MethodFlag_None = 0, + MethodFlag_Signal = 1 +}; MiniAstDumperASTAction::MiniAstDumperASTAction() { @@ -52,6 +63,7 @@ std::unique_ptr<ASTConsumer> MiniAstDumperASTAction::CreateASTConsumer(CompilerI MiniASTDumperConsumer::MiniASTDumperConsumer(CompilerInstance &ci) : m_ci(ci) + , m_accessSpecifierManager(new AccessSpecifierManager(ci)) { auto &sm = m_ci.getASTContext().getSourceManager(); const FileEntry *fileEntry = sm.getFileEntryForID(sm.getMainFileID()); @@ -93,6 +105,8 @@ MiniASTDumperConsumer::~MiniASTDumperConsumer() bool MiniASTDumperConsumer::VisitDecl(Decl *decl) { + m_accessSpecifierManager->VisitDeclaration(decl); + if (auto tsd = dyn_cast<ClassTemplateSpecializationDecl>(decl)) { // llvm::errs() << "ClassTemplateSpecializationDecl: " + tsd->getQualifiedNameAsString() + "\n"; } else if (auto rec = dyn_cast<CXXRecordDecl>(decl)) { @@ -126,6 +140,11 @@ bool MiniASTDumperConsumer::VisitDecl(Decl *decl) if (func->getTemplatedKind() == FunctionDecl::TK_FunctionTemplate) { // Already handled when catching FunctionTemplateDecl. When we write func->getTemplatedDecl(). + + if (func->getQualifiedNameAsString() == "qobject_cast") { + llvm::errs() << "skipping! " << func << "\n"; + } + return true; } @@ -158,20 +177,38 @@ void MiniASTDumperConsumer::HandleTranslationUnit(ASTContext &ctx) void MiniASTDumperConsumer::dumpCXXMethodDecl(CXXMethodDecl *method, CborEncoder *encoder) { - CborEncoder recordMap; - cborCreateMap(encoder, &recordMap, 2); + CborEncoder methodMap; + cborCreateMap(encoder, &methodMap, CborIndefiniteLength); - cborEncodeString(recordMap, "name"); - cborEncodeString(recordMap, method->getQualifiedNameAsString().c_str()); + cborEncodeString(methodMap, "name"); + cborEncodeString(methodMap, method->getQualifiedNameAsString().c_str()); - cborEncodeString(recordMap, "id"); - cborEncodeInt(recordMap, int64_t(method)); + cborEncodeString(methodMap, "id"); + cborEncodeInt(methodMap, int64_t(method)); - cborCloseContainer(encoder, &recordMap); + int64_t flags = 0; + + if (m_accessSpecifierManager->qtAccessSpecifierType(method) == QtAccessSpecifier_Signal) + flags |= MethodFlag_Signal; + + if (flags) { + cborEncodeString(methodMap, "method_flags"); + cborEncodeInt(methodMap, flags); + } + + cborCloseContainer(encoder, &methodMap); } void MiniASTDumperConsumer::dumpFunctionDecl(FunctionDecl *func, CborEncoder *encoder) { + + if (func->getQualifiedNameAsString() == "qobject_cast") { + llvm::errs() << "registering! " << func + << " " << func->getBeginLoc().printToString(m_ci.getSourceManager()) + << "\n"; + } + + CborEncoder recordMap; cborCreateMap(encoder, &recordMap, 3); @@ -205,9 +242,14 @@ void MiniASTDumperConsumer::dumpCXXRecordDecl(CXXRecordDecl *rec, CborEncoder *e const SourceLocation loc = clazy::getLocStart(rec); dumpLocation(loc, &recordMap); - if (clazy::isQObject(rec)) { // TODO: Use flags - cborEncodeString(recordMap, "isQObject"); - cborEncodeBool(recordMap, true); + int64_t flags = 0; + + if (clazy::isQObject(rec)) + flags |= ClassFlag_QObject; + + if (flags) { + cborEncodeString(recordMap, "class_flags"); + cborEncodeInt(recordMap, flags); } cborEncodeString(recordMap, "methods"); @@ -236,7 +278,24 @@ void MiniASTDumperConsumer::dumpCallExpr(CallExpr *callExpr, CborEncoder *encode if (isBuiltin) //We don't need them now return; - func = func->getCanonicalDecl(); + auto method = dyn_cast<CXXMethodDecl>(func); + if (method) { + // For methods we store the declaration + func = clazy::getFunctionDeclaration(method); + } + + if (func->getQualifiedNameAsString() == "qobject_cast") { + llvm::errs() << "foo-call " + << func + << "; original=" << callExpr->getDirectCallee() + << "; funcloc " << func->getBeginLoc().printToString(m_ci.getSourceManager()) + << "; original-loc= " << callExpr->getDirectCallee()->getBeginLoc().printToString(m_ci.getSourceManager()) + + << "; " << func->getTemplatedKind() << " ; " << callExpr->getDirectCallee()->getTemplatedKind() + + << "\n"; + } + CborEncoder callMap; cborCreateMap(encoder, &callMap, 3); diff --git a/src/MiniAstDumper.h b/src/MiniAstDumper.h index 3a1cd85f..e0dfdbea 100644 --- a/src/MiniAstDumper.h +++ b/src/MiniAstDumper.h @@ -42,6 +42,8 @@ class Decl; class Stmt; } +class AccessSpecifierManager; + class MiniAstDumperASTAction : public clang::PluginASTAction { public: @@ -87,6 +89,8 @@ private: std::unordered_map<unsigned int, std::string> m_fileIds; std::string m_currentCppFile; + + AccessSpecifierManager *const m_accessSpecifierManager; }; #endif |