16 from Tool.callsite
import makeCallsiteRecord
29 for node
in ast.iter_child_nodes(root):
30 if isinstance(node,ast.ClassDef):
31 if len(node.bases)==0:
42 if base.split(
'.')[0]
in importDict:
43 base=importDict[base.split(
'.')[0]]
51 for n
in ast.iter_child_nodes(node):
52 if isinstance(n,ast.FunctionDef):
56 callVisitor=GetFuncCall()
57 callVisitor.dfsVisit(node)
58 callInfos=callVisitor.func_call
59 for Tuple
in callInfos:
60 callLst.append(Tuple[0])
62 ansLst.append((bases,defLst,callLst))
85 name_parts=callName.split(
'.')
91 for i
in range(len(codeLst)):
94 if f
"{prefix}({paraStr})".replace(
' ',
'').replace(
"'",
'').replace(
'"',
'')
in codeLst[i].replace(
' ',
'').replace(
"'",
'').replace(
'"',
'').rstrip(
'\n'):
99 for i
in range(len(codeLst)):
100 if f
"{prefix}(".replace(
' ',
'')
in codeLst[i].replace(
' ',
'').rstrip(
'\n'):
108 s=codeLst[index].strip()
109 if '#' in s
and '=' in s:
111 tempNode=ast.parse(s)
112 s=ast.unparse(tempNode)
117 if name_parts[0]!=
'self':
118 if f
"{name_parts[0]}="==s[0:len(name_parts[0])+1]:
120 firstModify=s[pos+1:]+
'.'+
'.'.join(name_parts[1:])
122 prefix=s[pos+1:].split(
'(',1)[0]
123 paraStr=s[pos+1:].split(
'(',1)[-1].rstrip(
')')
128 if len(name_parts)>2
and f
"{'.'.join(name_parts[0:2])}=" in s:
130 firstModify=s[pos+1:]+
'.'+
'.'.join(name_parts[2:])
131 prefix=s[pos+1:].split(
'(',1)[0]
132 paraStr=s[pos+1:].split(
'(',1)[-1].rstrip(
')')
158 name_parts = callName.split(
'.')
159 firstModify = callName
161 if name_parts[0]
in withitemCallName:
162 withitem = withitemCallName[name_parts[0]]
163 if isinstance(withitem, list):
164 candidates = withitem
165 if lineno
is not None:
168 for item
in candidates:
169 start = item.get(
'lineno')
170 end = item.get(
'end_lineno')
171 if start
is not None and end
is not None and start <= lineno <= end:
176 candidates = sorted(candidates, key=
lambda item: item.get(
'lineno')
or -1)
177 withitem = candidates[-1].get(
'callName')
181 firstModify = withitem +
'.' +
'.'.join(name_parts[1:])
208 if pcresolveLookup
is not None and filePath
in pcresolveLookup:
209 records = pcresolveLookup[filePath]
210 return records, records
212 with open(filePath,
'r',encoding=
'UTF-8')
as f:
215 codeLst=f.readlines()
217 root_node=ast.parse(codeText,filename=
'<unknown>',mode=
'exec')
220 import_visitor=Import()
221 import_visitor.visit(root_node)
222 md_names=import_visitor.get_md_name()
225 withitem_visitor = WithVisitor()
226 withitem_visitor.visit(root_node)
227 withitem_call_names = withitem_visitor.get_withitem_call()
230 call_visitor=GetFuncCall()
231 call_visitor.dfsVisit(root_node)
232 all_func_calls=call_visitor.func_call
237 for callName,paraStr,callState,lineno,colOffset,endLineNo,endColOffset
in all_func_calls:
238 name_parts=callName.split(
'.')
239 if 'self' in name_parts[0]:
240 selfAPIs.append((callName,paraStr,callState,lineno,colOffset,endLineNo,endColOffset))
244 secondModify=firstModify
247 if len(withitem_call_names) !=0:
248 firstModify =
modifyWithName(callName, withitem_call_names, lineno)
249 secondModify = firstModify
255 name_parts=secondModify.split(
'.')
256 firstParts=name_parts[0]
257 pos=firstParts.find(
'(')
259 temp=firstParts[0:pos]
265 secondModify=(md_names[temp]+res+
'.'+
'.'.join(name_parts[1:])).rstrip(
'.')
269 apiFormatDict[(secondModify,paraStr,callState,lineno,colOffset,endLineNo,endColOffset)]=(callName,paraStr,callState,lineno,colOffset,endLineNo,endColOffset)
273 selfInfo=
getSelfAPI(root_node,md_names,libName)
275 for callName,paraStr,callState,lineno,colOffset,endLineNo,endColOffset
in selfAPIs:
276 name_parts=callName.split(
'.')
277 for bases,defLst,callLst
in selfInfo:
278 if callName
in callLst
and name_parts[-1]
not in defLst:
279 name=bases[0]+
'.'+
'.'.join(name_parts[1:])
280 apiFormatDict[(name,paraStr,callState,lineno,colOffset,endLineNo,endColOffset)]=(callName,paraStr,callState,lineno,colOffset,endLineNo,endColOffset)
284 callsiteParamRecords={}
285 for key,value
in apiFormatDict.items():
286 if key[0].split(
'.')[0]==libName:
287 formatAPI=f
"{key[0]}({key[1]})"
299 callsiteRecords[record[
'id']]=record
300 callsiteParamRecords[record[
'id']]=record
303 sortedCallsiteRecords=dict(sorted(callsiteRecords.items(),key=
lambda x:(x[1][
'lineno'],x[1][
'col_offset'])))
304 sortedCallsiteParamRecords=dict(sorted(callsiteParamRecords.items(),key=
lambda x:(x[1][
'lineno'],x[1][
'col_offset'])))
305 return sortedCallsiteRecords,sortedCallsiteParamRecords
307 except SyntaxError
as e:
308 print(f
"when extract invoked API, parsed {filePath} failed: {e}")
def makeCallsiteRecord(file_path, call_text, format_api, parameters, lineno, col_offset, end_lineno=None, end_col_offset=None, proj_path=None)
Make callsite record 构造调用点记录
def getSelfAPI(root, importDict, libName)
Extract method calls in a custom class inherited from a lib class 获取从库API继承的自定义类中的库API方法调用
def getCallFunction(filePath, libName, projPath=None, pcresolveLookup=None)
Extract all API calls from a given .py file 每次传进来一个.py文件,抽取所有的调用API.
def modifyWithName(callName, withitemCallName, lineno=None)
Restore the conventional API call path in the withitem (including AsyncWith) call form 还原withitemAPI调...
def modifyFirstName(prefix, callName, paraStr, codeLst)
Restore the conventional API call path by modifying the first name of the API prefix 通过修改API赋值调用前缀还原完...