Skip to content

Commit

Permalink
Merge pull request #4248 from gartung/clangSA-better-virtual-linkage
Browse files Browse the repository at this point in the history
Virtual function calls of the for Foo::bar() are not linked to their override
  • Loading branch information
ktf committed Jun 16, 2014
2 parents c122500 + a236569 commit 7a94a07
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 33 deletions.
61 changes: 31 additions & 30 deletions Utilities/StaticAnalyzers/scripts/statics.py
Expand Up @@ -3,9 +3,11 @@
topfunc = re.compile("::(produce|analyze|filter|beginLuminosityBlock|beginRun)\(")
baseclass = re.compile("edm::(one::|stream::|global::)?ED(Producer|Filter|Analyzer)(Base)?")
farg = re.compile("\(.*\)")
fre = re.compile("function")

statics = set()
toplevelfuncs = set()
skipfunc = re.compile("(edm::EDProductGetter::getIt|edm::Event::|edm::eventsetup::EventSetupRecord::get|edm::eventsetup::DataProxy::getImpl|edm::EventPrincipal::unscheduledFill|edm::ServiceRegistry::get|edm::eventsetup::EventSetupRecord::getImplementation|edm::eventsetup::EventSetupRecord::getFromProxy|edm::eventsetup::DataProxy::get)")
skipfunc = re.compile("(edm::(LuminosityBlock::|Run::|Event::)getBy(Label|Token))|(fwlite::|edm::EDProductGetter::getIt|edm::Event::|edm::eventsetup::EventSetupRecord::get|edm::eventsetup::DataProxy::getImpl|edm::EventPrincipal::unscheduledFill|edm::ServiceRegistry::get|edm::eventsetup::EventSetupRecord::getImplementation|edm::eventsetup::EventSetupRecord::getFromProxy|edm::eventsetup::DataProxy::get)")
skipfuncs=set()

import networkx as nx
Expand All @@ -14,43 +16,42 @@
f = open('db.txt')

for line in f :
fields = line.split("'")
if fields[2] == ' calls function ' :
if skipfunc.search(line) : skipfuncs.add(line)
else : G.add_edge(fields[1],fields[3],kind=fields[2])
if fields[2] == ' overrides function ' :
if baseclass.search(fields[3]) :
if topfunc.search(fields[3]) : toplevelfuncs.add(fields[1])
G.add_edge(fields[1],fields[3],kind=' overrides function ')
else :
if fre.search(line):
fields = line.split("'")
if fields[2] == ' calls function ':
if skipfunc.search(line) : skipfuncs.add(line)
else : G.add_edge(fields[3],fields[1],kind=' calls function ')
if fields[2] == ' static variable ' :
G.add_edge(fields[1],fields[3],kind=' static variable ')
statics.add(fields[3])
else : G.add_edge(fields[1],fields[3],kind=fields[2])
if fields[2] == ' overrides function ' :
if baseclass.search(fields[3]) :
if topfunc.search(fields[3]) : toplevelfuncs.add(fields[1])
G.add_edge(fields[1],fields[3],kind=fields[2])
else :
if skipfunc.search(line) : skipfuncs.add(line)
else : G.add_edge(fields[3],fields[1],kind=' calls function ')
if fields[2] == ' static variable ' :
G.add_edge(fields[1],fields[3],kind=' static variable ')
statics.add(fields[3])
f.close()

for static in statics:
for tfunc in toplevelfuncs:
for tfunc in sorted(toplevelfuncs):
for static in sorted(statics):
if nx.has_path(G,tfunc,static):
path = nx.shortest_path(G,tfunc,static)
print "Non-const static variable \'"+re.sub(farg,"()",static)+"\' is accessed in call stack ",
print " \'",
for p in path :
print re.sub(farg,"()",p)+"; ",
print " \'. ",

print "Non-const static variable \'"+re.sub(farg,"()",static)+"' is accessed in call stack '",
for i in range(0,len(path)-1) :
print re.sub(farg,"()",path[i])+G[path[i]][path[i+1]]['kind'],
print re.sub(farg,"()",path[i+1])+"' ,",
for key in G[tfunc].keys() :
if 'kind' in G[tfunc][key] and G[tfunc][key]['kind'] == ' overrides function ' :
print "'"+re.sub(farg,"()",tfunc)+"'"+G[tfunc][key]['kind']+"'"+re.sub(farg,"()",key)+"'",
print ""
path = nx.shortest_path(G,tfunc,static)
print "'"+re.sub(farg,"()",tfunc)+"' overrides '"+re.sub(farg,"()",key)+"'",
print

print "In call stack ' ",
for p in path:
print re.sub(farg,"()",p)+"; ",
print "\'",
print " non-const static variable \'"+re.sub(farg,"()",static)+"\' is accessed. ",
for i in range(0,len(path)-1) :
print re.sub(farg,"()",path[i])+G[path[i]][path[i+1]]['kind'],
print re.sub(farg,"()",path[i+1])+"' is accessed ,",
for key in G[tfunc].keys() :
if 'kind' in G[tfunc][key] and G[tfunc][key]['kind'] == ' overrides function ' :
print "'"+re.sub(farg,"()",tfunc)+"'"+G[tfunc][key]['kind']+"'"+re.sub(farg,"()",key)+"'",
print "'"+re.sub(farg,"()",tfunc)+"' overrides '"+re.sub(farg,"()",key)+"'",
print

18 changes: 15 additions & 3 deletions Utilities/StaticAnalyzers/src/FunctionDumper.cpp
Expand Up @@ -104,7 +104,19 @@ void FDumper::VisitCallExpr( CallExpr *CE ) {
std::string tname = "";
if ( pPath != NULL ) tname += std::string(pPath);
tname+="/tmp/function-dumper.txt.unsorted";
std::string ostring = "function '"+ mdname + "' " + "calls function '" + mname + "'\n";
std::string ostring;
CXXMemberCallExpr * CXE = llvm::dyn_cast<CXXMemberCallExpr>(CE);
if (CXE) {
const CXXMethodDecl * CD = CXE->getMethodDecl();
const CXXRecordDecl * RD = CXE->getRecordDecl();
const Expr * IOA = CXE->getImplicitObjectArgument();
const CXXMethodDecl * AMD = llvm::dyn_cast<CXXMethodDecl>(D);
if ( AMD && CD && RD && CD->isVirtual() && RD == AMD->getParent() ) ostring = "function '"+ mdname + "' " + "calls function '" + mname + " virtual'\n";
else ostring = "function '"+ mdname + "' " + "calls function '" + mname + "'\n";
} else {
if (FD->isVirtualAsWritten() || FD->isPure()) ostring = "function '"+ mdname + "' " + "calls function '" + mname + " virtual'\n";
else ostring = "function '"+ mdname + "' " + "calls function '" + mname + "'\n";
}
std::ofstream file(tname.c_str(),std::ios::app);
file<<ostring;
VisitChildren(CE);
Expand All @@ -124,9 +136,9 @@ void FunctionDumper::checkASTDecl(const CXXMethodDecl *MD, AnalysisManager& mgr,
std::string tname="";
if ( pPath != NULL ) tname += std::string(pPath);
tname += "/tmp/function-dumper.txt.unsorted";
for (auto I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I!=E; ++I) {
for (auto I = MD->begin_overridden_methods(), E = MD->end_overridden_methods(); I!=E; ++I) {
std::string oname = support::getQualifiedName(*(*I));
std::string ostring = "function '" + mname + "' " + "overrides function '" + oname + "'\n";
std::string ostring = "function '" + mname + "' " + "overrides function '" + oname + " virtual'\n";
std::ofstream file(tname.c_str(),std::ios::app);
file<<ostring;
}
Expand Down

0 comments on commit 7a94a07

Please sign in to comment.