from __future__ import generators
from bike.globals import *
from bike.parsing.fastparserast import Module,Class,Function,getRoot,Instance
from bike.query.common import Match,MatchFinder,\
getScopeForLine, indexToCoordinates, \
translateSourceCoordsIntoASTNode, scanScopeForMatches,\
globalScanForMatches, isAMethod, convertNodeToMatchObject
from compiler.ast import AssName,Name,Getattr,AssAttr
import compiler
from findDefinition import findDefinitionFromASTNode
from bike.query.getTypeOf import getTypeOfExpr,UnfoundType
from bike.query.relationships import getRootClassesOfHierarchy
from bike import log
from bike.parsing.load import getSourceNode
class CouldntFindDefinitionException(Exception):
pass
def findReferencesIncludingDefn(filename,lineno,col):
return findReferences(filename,lineno,col,1)
def findReferences(filename,lineno,col,includeDefn=0):
sourcenode = getSourceNode(filename)
node = translateSourceCoordsIntoASTNode(filename,lineno,col)
assert node is not None
scope,defnmatch = getDefinitionAndScope(sourcenode,lineno,node)
try:
for match in findReferencesIncludingDefn_impl(sourcenode,node,
scope,defnmatch):
if not includeDefn and match == defnmatch:
continue # don't return definition
else:
yield match
except CouldntFindDefinitionException:
raise CouldntFindDefinitionException("Could not find definition. Please locate manually (maybe using find definition) and find references from that")
def findReferencesIncludingDefn_impl(sourcenode,node,scope,defnmatch):
if isinstance(node,Name) or isinstance(node,AssName):
return generateRefsToName(node.name,scope,sourcenode,defnmatch)
elif isinstance(node,Getattr) or isinstance(node,AssAttr):
exprtype = getTypeOfExpr(scope,node.expr)
if exprtype is None or isinstance(exprtype,UnfoundType):
raise CouldntFindDefinitionException()
if isinstance(exprtype,Instance):
exprtype = exprtype.getType()
return generateRefsToAttribute(exprtype,node.attrname)
else:
targetname = node.attrname
return globalScanForMatches(sourcenode.filename,
NameRefFinder(targetname, defnmatch),
targetname, )
if match is not None:
return match
elif isinstance(node,compiler.ast.Function) or \
isinstance(node,compiler.ast.Class):
return handleClassOrFunctionRefs(scope, node, defnmatch)
else:
assert 0,"Seed to references must be Name,Getattr,Function or Class"
def handleClassOrFunctionRefs(scope, node, defnmatch):
if isAMethod(scope,node):
for ref in generateRefsToAttribute(scope,node.name):
yield ref
else:
#yield convertNodeToMatchObject(node,100)
yield defnmatch
for ref in generateRefsToName(node.name,scope,
scope.module.getSourceNode(),
defnmatch):
yield ref
def getDefinitionAndScope(sourcenode,lineno,node):
scope = getScopeForLine(sourcenode,lineno)
if scope.getStartLine() == lineno and \
scope.matchesCompilerNode(node): # scope is the node
return scope.getParent(), convertNodeToMatchObject(scope,100)
defnmatch = findDefinitionFromASTNode(scope,node)
if defnmatch is None:
raise CouldntFindDefinitionException()
scope = getScopeForLine(sourcenode,defnmatch.lineno)
return scope,defnmatch
def generateRefsToName(name,scope,sourcenode,defnmatch):
assert scope is not None
if isinstance(scope,Function):
# search can be limited to scope
return scanScopeForMatches(sourcenode,scope,
NameRefFinder(name,defnmatch),
name)
else:
return globalScanForMatches(sourcenode.filename,
NameRefFinder(name,defnmatch),
name)
class NameRefFinder(MatchFinder):
def __init__(self, targetstr,targetMatch):
self.targetstr = targetstr
self.targetMatch = targetMatch
def visitName(self, node):
if node.name == self.targetstr:
potentualMatch = findDefinitionFromASTNode(self.scope, node)
if potentualMatch is not None and \
potentualMatch == self.targetMatch:
self.appendMatch(node.name)
self.popWordsUpTo(node.name)
visitAssName = visitName
def visitFunction(self, node):
self.popWordsUpTo(node.name)
for arg, default in self.zipArgs(node.argnames, node.defaults):
if arg == self.targetstr:
self.appendMatch(arg)
self.popWordsUpTo(arg)
if default is not None:
self.visit(default)
self.visit(node.code)
def visitFrom(self, node):
for elem in node.modname.split("."):
self.popWordsUpTo(elem)
for name, alias in node.names:
if name == self.targetstr:
if alias is not None:
pretendNode = Name(alias)
else:
pretendNode = Name(name)
if findDefinitionFromASTNode(self.scope, pretendNode) \
== self.targetMatch:
self.appendMatch(name)
self.popWordsUpTo(name)
if alias is not None:
self.popWordsUpTo(alias)
def visitGetattr(self, node):
for c in node.getChildNodes():
self.visit(c)
if node.attrname == self.targetstr:
defn = findDefinitionFromASTNode(self.scope, node)
if defn is not None and defn == self.targetMatch:
self.appendMatch(node.attrname)
self.popWordsUpTo(node.attrname)
def visitImport(self, node):
for name, alias in node.names:
if name.split(".")[-1] == self.targetstr:
getattr = self.createGetattr(name)
if findDefinitionFromASTNode(self.scope, getattr) == self.targetMatch:
self.appendMatch(self.targetstr)
for nameelem in name.split("."):
self.popWordsUpTo(nameelem)
if alias is not None:
self.popWordsUpTo(alias)
def createGetattr(self,fqn):
node = Name(fqn[0])
for name in fqn.split(".")[1:]:
node = Getattr(node,name)
return node
def generateRefsToAttribute(classobj,attrname):
rootClasses = getRootClassesOfHierarchy(classobj)
attrRefFinder = AttrbuteRefFinder(rootClasses,attrname)
for ref in globalScanForMatches(classobj.filename, attrRefFinder, attrname):
yield ref
print >>log.progress,"Done"
class AttrbuteRefFinder(MatchFinder):
def __init__(self,rootClasses,targetAttribute):
self.rootClasses = rootClasses
self.targetAttributeName = targetAttribute
def visitGetattr(self, node):
for c in node.getChildNodes():
self.visit(c)
if node.attrname == self.targetAttributeName:
exprtype = getTypeOfExpr(self.scope,node.expr)
if isinstance(exprtype,Instance) and \
self._isAClassInTheSameHierarchy(exprtype.getType()):
self.appendMatch(self.targetAttributeName)
elif isinstance(exprtype,UnfoundType) or \
exprtype is None: # couldn't find type, so not sure
self.appendMatch(self.targetAttributeName,50)
else:
pass # definately not a match
self.popWordsUpTo(node.attrname)
visitAssAttr = visitGetattr
def visitFunction(self,node): # visit methods
if node.name == self.targetAttributeName:
parentScope = self.scope.getParent()
#print parentScope
#print self.targetClasses
if isinstance(parentScope,Class) and \
self._isAClassInTheSameHierarchy(parentScope):
self.appendMatch(node.name)
for c in node.getChildNodes():
self.visit(c)
def _isAClassInTheSameHierarchy(self,classobj):
#return classobj in self.targetClasses
targetRootClasses = getRootClassesOfHierarchy(classobj)
for rootclass in self.rootClasses:
if rootclass in targetRootClasses:
return True
return False
|