Пример #1
0
class PfisGraphWithSimilarPatches(PfisGraphWithVariants):
    def __init__(self,
                 dbFilePath,
                 langHelper,
                 projSrc,
                 variantsDb,
                 stopWords=[],
                 verbose=False):
        PfisGraphWithVariants.__init__(self, dbFilePath, langHelper, projSrc,
                                       stopWords, verbose)
        self.variantsDb = variantsDb
        self.knownMethodPatches = KnownPatches(langHelper, variantsDb)

    def _addEdge(self, node1, node2, node1Type, node2Type, edgeType):
        if node1Type != NodeType.METHOD and node2Type != NodeType.METHOD:
            PfisGraphWithVariants._addEdge(self, node1, node2, node1Type,
                                           node2Type, edgeType)

        else:
            node1Equivalent = self._getEquivalentNode(node1, node1Type)
            node2Equivalent = self._getEquivalentNode(node2, node2Type)
            PfisGraphWithVariants._addEdge(self, node1Equivalent,
                                           node2Equivalent, node1Type,
                                           node2Type, edgeType)

    def _getEquivalentNode(self, node, nodeType):
        if nodeType != NodeType.METHOD:
            return node

        elif self.langHelper.excludeMethod(node):
            return node

        else:
            nodeEquivalent = self.getEquivalentGraphNode(node)
            return nodeEquivalent

    def getEquivalentGraphNode(self, node):
        #TODO: See why there are TWO different methods
        self.knownMethodPatches.addFilePatch(node)
        method = self.knownMethodPatches.findMethodByFqn(node)
        return method.fqn

    def getFqnOfEquivalentNode(self, fqn):
        equivalentPatch = self.knownMethodPatches.findMethodByFqn(fqn)
        return equivalentPatch.fqn

    def containsNode(self, node):
        if self.langHelper.isMethodFqn(node):
            equivalentNode = self.getFqnOfEquivalentNode(node)
            return equivalentNode in self.graph.nodes()
        return node in self.graph.nodes()

    def getNode(self, nodeName):
        equivalentNode = nodeName
        if self.langHelper.isMethodFqn(nodeName):
            equivalentNode = self.getFqnOfEquivalentNode(nodeName)
        return self.graph.node[equivalentNode]
Пример #2
0
 def __init__(self,
              dbFilePath,
              langHelper,
              projSrc,
              variantsDb,
              stopWords=[],
              verbose=False):
     PfisGraphWithVariants.__init__(self, dbFilePath, langHelper, projSrc,
                                    stopWords, verbose)
     self.variantsDb = variantsDb
     self.knownMethodPatches = KnownPatches(langHelper, variantsDb)
Пример #3
0
class PfisGraphWithSimilarPatches(PfisGraphWithVariants):
	def __init__(self, dbFilePath, langHelper, projSrc, variantsDb, stopWords=[], verbose=False):
		PfisGraphWithVariants.__init__(self, dbFilePath, langHelper, projSrc, stopWords, verbose)
		self.variantsDb = variantsDb
		self.knownMethodPatches = KnownPatches(langHelper, variantsDb)

	def _addEdge(self, node1, node2, node1Type, node2Type, edgeType):
		if node1Type != NodeType.METHOD and node2Type != NodeType.METHOD:
			PfisGraphWithVariants._addEdge(self, node1, node2, node1Type, node2Type, edgeType)

		else:
			node1Equivalent = self._getEquivalentNode(node1, node1Type)
			node2Equivalent = self._getEquivalentNode(node2, node2Type)
			PfisGraphWithVariants._addEdge(self, node1Equivalent, node2Equivalent, node1Type, node2Type, edgeType)


	def _getEquivalentNode(self, node, nodeType):
		if nodeType != NodeType.METHOD:
			return node

		elif self.langHelper.excludeMethod(node):
			return node

		else:
			nodeEquivalent = self.getEquivalentGraphNode(node)
			return nodeEquivalent

	def getEquivalentGraphNode(self, node):
		#TODO: See why there are TWO different methods
		self.knownMethodPatches.addFilePatch(node)
		method = self.knownMethodPatches.findMethodByFqn(node)
		return method.fqn

	def getFqnOfEquivalentNode(self, fqn):
		equivalentPatch = self.knownMethodPatches.findMethodByFqn(fqn)
		return equivalentPatch.fqn

	def containsNode(self, node):
		if self.langHelper.isMethodFqn(node):
			equivalentNode = self.getFqnOfEquivalentNode(node)
			return equivalentNode in self.graph.nodes()
		return node in self.graph.nodes()

	def getNode(self, nodeName):
		equivalentNode = nodeName
		if self.langHelper.isMethodFqn(nodeName):
			equivalentNode = self.getFqnOfEquivalentNode(nodeName)
		return self.graph.node[equivalentNode]
Пример #4
0
    def __addAdjacencyNodesUpTo(self, conn, prevEndTimestamp, newEndTimestamp):
        knownPatches = KnownPatches(self.langHelper)
    
        print "\tProcessing adjacency. Adding adjacency edges to the graph..."
    
        c = conn.cursor()
        c.execute(self.ADJACENCY_QUERY, [prevEndTimestamp, newEndTimestamp])
        
        for row in c:
            target, referrer = self.langHelper.fixSlashes(row['target']), int(row['referrer'])
            
            knownPatches.addFilePatch(target);
            method = knownPatches.findMethodByFqn(target);
            method.startOffset = referrer
        
        c.close()
        
        adjacentMethodLists = knownPatches.getAdajecentMethods()
        
        for methods in adjacentMethodLists:
            for i in range(1, len(methods)):
                self._addEdge(methods[i].fqn, methods[i - 1].fqn,
                              NodeType.METHOD,
                              NodeType.METHOD,
                              EdgeType.ADJACENT)
#                 print '\t\tAdded edge from '
#                 print '\t\t\t' + methods[i - 1].fqn + ' to '
#                 print '\t\t\t' + methods[i].fqn
        
        print "\tDone processing adjacency."
        self.__printGraphStats()
Пример #5
0
    def __init__(self, dbFilePath, langHelper, projectFolderPath, verbose = False):
        self.dbFilePath = dbFilePath
        self.langHelper = langHelper
        self.projectFolderPath = projectFolderPath
        self.VERBOSE_PATH = verbose

        self.__fileNavigations = []
        self._navigations = []

        self._name = NavigationPath.DEFAULT
        #Do not account for similar patches across variants
        self.knownPatches = KnownPatches(langHelper)

        conn = sqlite3.connect(self.dbFilePath)
        conn.row_factory = sqlite3.Row

        if self.VERBOSE_PATH:
            print 'Building path...'
        self.__findFileNavigationsInDb(conn)
        self.__findMethodsForFileNavigations(conn)
        if self.VERBOSE_PATH:
            print 'Done building path.'
        self._printNavigations()
        conn.close()
Пример #6
0
class NavigationPath(object):

    DEFAULT = "Default"
    VARIANT_AWARE = "VariantAware"
    VARIANT_AWARE_COLLAPSED = "VariantAwareCollapsed"
    METHOD_DECLARATIONS_QUERY = "SELECT timestamp, action, target, referrer from logger_log WHERE action IN ('Method declaration', 'Method declaration offset', 'Method declaration length') AND timestamp <= ? ORDER BY timestamp"

    def __init__(self, dbFilePath, langHelper, projectFolderPath, verbose = False):
        self.dbFilePath = dbFilePath
        self.langHelper = langHelper
        self.projectFolderPath = projectFolderPath
        self.VERBOSE_PATH = verbose

        self.__fileNavigations = []
        self._navigations = []

        self._name = NavigationPath.DEFAULT
        #Do not account for similar patches across variants
        self.knownPatches = KnownPatches(langHelper)

        conn = sqlite3.connect(self.dbFilePath)
        conn.row_factory = sqlite3.Row

        if self.VERBOSE_PATH:
            print 'Building path...'
        self.__findFileNavigationsInDb(conn)
        self.__findMethodsForFileNavigations(conn)
        if self.VERBOSE_PATH:
            print 'Done building path.'
        self._printNavigations()
        conn.close()


    def getNavPathType(self):
        return self._name

    def __findFileNavigationsInDb(self, conn):
        # Here, we find all the instances of Text selection offset actions in
        # the PFIG log. These are stored into the self.__fileNavigations list. We
        # remove any obvious duplicates that have the same file path and offset
        # in this function. We store time stamps here since they will be used to
        # determine if self.knownMethods entries need to be added or updated.
        c = conn.cursor()
        c.execute(self.langHelper.TEXT_SELECTION_OFFSET_QUERY)

        prevFilePath = None
        prevOffset = None

        for row in c:
            timestamp, filePath, offset = \
                str(iso8601.parse_date(row['timestamp'])), row['target'], int(row['referrer'])

            if prevFilePath != filePath or prevOffset != offset: #This is for a Java PFIG bug / peculiarity -- duplicate navs to same offset in  Java DB
                    if self.langHelper.hasCorrectExtension(filePath):
                        self.__fileNavigations.append(FileNavigation(timestamp, filePath, offset))

            prevFilePath = filePath
            prevOffset = offset
        c.close()

    def __findMethodsForFileNavigations(self, conn):
        # Here we map the file paths and offsets in the fileNavigations list to
        # FQNs of methods. This is done by querying for all the Method
        # declarations within the database and storing that data to the
        # self.knownMethods object. The insertions into knownMethods will create
        # entries if they are new or update them if they already exist. Since
        # code can be changed between navigations, we need to update
        # self.knownMethods to reflect the most recent state of the code up to
        # each navigation.
        # After building the known methods, we test an entry from
        # fileNavigations against the set of known methods by offset. This is
        # what maps Text selection offsets to methods.
        prevNavigation = None
        postProcessing = False

        # Iterate over the data gathered from the Text selection offsets
        for i in range(len(self.__fileNavigations)):
            toFileNavigation = self.__fileNavigations[i]
            if self.VERBOSE_PATH:
                print '\tProcessing text selection offset: ' + str(toFileNavigation)

            # For every navigation's timestamp, we fill the knownMethods object
            # with the details of every method declaration up to the timestamp
            # of the toFileNavigation. The knownMethods object will be queried to
            # determine in which method (if any) a text selection offset occurs.

            # Note that the queries here are by a method's FQN. This allows us
            # to update the method's declaration info if it gets updated at some
            # point in the future.

            c = conn.execute(self.METHOD_DECLARATIONS_QUERY, [toFileNavigation.timestamp])
            for row in c:
                action, target, referrer = row['action'], \
                    row['target'], row['referrer']

                if action == 'Method declaration':
                    self.knownPatches.addFilePatch(referrer)
                elif action == 'Method declaration offset':
                    method = self.knownPatches.findMethodByFqn(target)
                    if method is not None:
                        method.startOffset = int(referrer)
                elif action == 'Method declaration length':
                    method = self.knownPatches.findMethodByFqn(target)
                    if method is not None:
                        method.length = int(referrer);

            # Recall that navigations contains the navigation data after its
            # been translated to methods and headers

            # If there was at least 1 navigation already, the to destination
            # from the previous navigation serves as this navigations from. A
            # clone is necessary since this may be later transformed into a
            # PFIG header and we don't want to affect the to destination from
            # the previous navigation.

            fromFileNavigation = None
            fromMethodPatch = None

            if len(self._navigations) > 0:
                prevNavigation = self._navigations[-1]
                fromFileNavigation = prevNavigation.toFileNav.clone()
                self.__addPFIGFileHeadersIfNeeded(conn, prevNavigation, toFileNavigation)
                fromMethodPatch = self.knownPatches.findMethodByOffset(fromFileNavigation.filePath, fromFileNavigation.offset)


            # We query known methods here to see if the offset of the current
            # toFileNavigation is among the known patches.
            toMethodPatch = self.knownPatches.findMethodByOffset(toFileNavigation.filePath, toFileNavigation.offset)


            # Create the navigation object representing this navigation
            navigation = Navigation(fromFileNavigation, toFileNavigation.clone())

            # Set method FQN data
            if navigation.fromFileNav is not None and fromMethodPatch is not None:
                navigation.fromFileNav.methodFqn = fromMethodPatch.fqn
            if navigation.toFileNav is not None and toMethodPatch is not None:
                navigation.toFileNav.methodFqn = toMethodPatch.fqn

            if not navigation.isToSameMethod():
                self._navigations.append(navigation)

                if navigation.fromFileNav is not None:
                    if navigation.fromFileNav.methodFqn is None:
                        postProcessing = True
                        navigation.fromFileNav.isGap = True
                        prevNavigation.toFileNav.isGap = True
            c.close()

        if postProcessing:
            self.__removeGapNavigations()

    def __removeGapNavigations(self):
        # We do a second pass over the navigations so that we remove any
        # parts of the navigation that have been previously identified as being
        # a navigation to a gap (a space between two method definitions).
        finalNavigations = []
        fromNav = None
        toNav = None
        foundGap = False

        for navigation in self._navigations:
            if not foundGap:
                if navigation.fromFileNav is None:
                    if navigation.toFileNav.isGap:
                        fromNav = navigation.fromFileNav
                        foundGap = True
                    else:
                        finalNavigations.append(navigation)
                elif not navigation.fromFileNav.isGap and navigation.toFileNav.isGap:
                    fromNav = navigation.fromFileNav
                    foundGap = True
                elif navigation.fromFileNav.isGap and navigation.toFileNav.isGap:
                    raise RuntimeError('removeGapNavigations: cannot have a navigation with a fromFileNav that is a gap without a prior navigation with a gap in the toFileNav')
                else:
                    if not navigation.isToSameMethod():
                        finalNavigations.append(navigation)
            elif foundGap:
                if navigation.fromFileNav.isGap and not navigation.toFileNav.isGap:
                    toNav = navigation.toFileNav
                    foundGap = False
                    newNavigation = Navigation(fromNav, toNav)
                    if not newNavigation.isToSameMethod():
                        finalNavigations.append(Navigation(fromNav, toNav))
                elif navigation.fromFileNav.isGap and navigation.toFileNav.isGap:
                    continue
                else:
                    raise RuntimeError('removeGapNavigations: cannot have a fromFileNav without a gap if the prior navigation had a gap in the toFileNav')

        self._navigations = finalNavigations

    def __addPFIGFileHeadersIfNeeded(self, conn, prevNav, currToFileNav):
        # If it's the first navigation, don't do anything
        if prevNav is None:
            return

        # If the previous navigation's to is not a known method and the current
        # navigation's from is the same unknown method, then this might need to
        # be converted to a header.
        #TODO: Sruti: Can this be otherwise? why this equality check?

        if prevNav.isToUnknown():
            previousNavToMethod = self.knownPatches.findMethodByOffset(prevNav.toFileNav.filePath, prevNav.toFileNav.offset)
            if previousNavToMethod is None:
                if self.VERBOSE_PATH:
                        print '\tChecking if ' + str(prevNav.toFileNav) + ' is a header...'
                headerData = PFIGFileHeader.addPFIGJavaFileHeader(conn, prevNav, currToFileNav, self.projectFolderPath, self.langHelper)

                # If headerData comes back as not None, then it was indeed a
                # header and needs to be added to navigation and
                # knownPatches.
                if headerData is not None:
                    if self.VERBOSE_PATH:
                        print '\tConverted to ' + headerData.fqn

                    # Add to the knownPatches
                    self.knownPatches.addFilePatch(headerData.fqn)

                    # Update the properties
                    method = self.knownPatches.findMethodByFqn(headerData.fqn)
                    method.startOffset = 0
                    method.length = headerData.length

                elif self.VERBOSE_PATH:
                    print '\tNot a header.'

    def getNavigation(self, i):
        return self._navigations[i]

    def getLength(self):
        return len(self._navigations)

    def _printNavigations(self):
        print "Navigation path:"
        for i in range(len(self._navigations)):
            navigation = self._navigations[i]
            print '\t' + str(i) + ':\t' + str(navigation)

    def getPriorNavToSimilarPatchIfAny(self, navNumber):
        raise Exception("Looking for similar patch in default navpath: ", navNumber)

    def getDefaultNavigation(self,i):
        return self._navigations[i]
Пример #7
0
	def __init__(self, dbFilePath, langHelper, projSrc, variantsDb, stopWords=[], verbose=False):
		PfisGraphWithVariants.__init__(self, dbFilePath, langHelper, projSrc, stopWords, verbose)
		self.variantsDb = variantsDb
		self.knownMethodPatches = KnownPatches(langHelper, variantsDb)