aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSergio Martins <sergio.martins@kdab.com>2019-06-11 22:41:54 +0100
committerSergio Martins <sergio.martins@kdab.com>2019-06-11 22:41:54 +0100
commit5515bf1587528e8898c7d7ab17b2dd6ed0a46b9e (patch)
tree90e5ea8143247ce8c680f1cb86c50369c3f5bcb1
parent5e226f6cf876137f2e71c9e57bd2a1e5221a64b4 (diff)
WIP
-rw-r--r--.gitignore2
-rwxr-xr-xdev-scripts/miniAstDumper.py75
-rw-r--r--src/MiniAstDumper.cpp83
-rw-r--r--src/MiniAstDumper.h4
4 files changed, 149 insertions, 15 deletions
diff --git a/.gitignore b/.gitignore
index f756c813..b75f8107 100644
--- a/.gitignore
+++ b/.gitignore
@@ -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