def _analyzeClassDepsNode_1(self, node, depsList, inLoadContext, inDefer=False):
        if node.type in ("file", "function", "catch"):
            top_scope = node.scope
        else:
            top_scope = scopes.find_enclosing(node)  # get enclosing scope of node
        # import pydb; pydb.debugger()
        for scope in top_scope.scope_iterator():  # walk through this and all nested scopes
            for global_name, scopeVar in scope.globals().items():  # get the global symbols { sym_name: ScopeVar }
                for node in scopeVar.uses:  # create a depsItem for all its uses
                    depsItem = self.qualify_deps_item(node, scope.is_load_time, scope.is_defer)
                    depsList.append(depsItem)  # and qualify them

        # Augment with feature dependencies introduces with qx.core.Environment.get("...") calls
        for envCall in variantoptimizer.findVariantNodes(node):
            className, classAttribute = self.getClassNameFromEnvKey(
                envCall.getChild("arguments").children[0].get("value", "")
            )
            if className:
                depsItem = DependencyItem(className, classAttribute, self.id, envCall.get("line", -1))
                depsItem.isCall = True  # treat as if actual call, to collect recursive deps
                # .inLoadContext
                # get 'qx' node of 'qx.core.Environment....'
                call_operand = envCall.getChild("operand").children[0]
                qx_idnode = treeutil.findFirstChainChild(call_operand)
                scope = qx_idnode.scope
                inLoadContext = scope.is_load_time  # get its scope's .is_load_time
                depsItem.isLoadDep = inLoadContext
                if inLoadContext:
                    depsItem.needsRecursion = True
                depsList.append(depsItem)

        return
Ejemplo n.º 2
0
    def getCombinedDeps(self,
                        variants,
                        config,
                        stripSelfReferences=True,
                        projectClassNames=True,
                        genProxy=None,
                        force=False,
                        tree=None):

        # init lists
        loadFinal = []
        runFinal = []

        # add static dependencies
        if genProxy == None:
            static, cached = self.dependencies(variants, force, tree=tree)
        else:
            static, cached = genProxy.dependencies(self.id, self.path,
                                                   variants)

        loadFinal.extend(static["load"])
        runFinal.extend(static["run"])

        # fix self-references
        if stripSelfReferences:
            loadFinal = [x for x in loadFinal if x.name != self.id]
            runFinal = [x for x in runFinal if x.name != self.id]

        # collapse multiple occurrences of the same class
        if projectClassNames:
            loads = loadFinal
            loadFinal = []
            for dep in loads:
                if dep.name not in (x.name for x in loadFinal):
                    loadFinal.append(dep)
            runs = runFinal
            runFinal = []
            for dep in runs:
                if dep.name not in (x.name for x in runFinal):
                    runFinal.append(dep)

        # add config dependencies
        crequire = config.get("require", {})
        if self.id in crequire:
            loadFinal.extend(
                DependencyItem(x, '', "|config|") for x in crequire[self.id])

        cuse = config.get("use", {})
        if self.id in cuse:
            runFinal.extend(
                DependencyItem(x, '', "|config|") for x in cuse[self.id])

        # result dict
        deps = {
            "load": loadFinal,
            "run": runFinal,
            "ignore": static['ignore'],
        }

        return deps, cached
Ejemplo n.º 3
0
 def depsItems_from_Json(self, deps_json):
     result = {"run": [], "load": [], "ignore": []}
     for category in ("run", "load"):
         for classId in deps_json[category]:
             if any([classId.startswith(x) for x in ("/resource/", "/translation/", "/locale/")]):
                 continue  # sorting out resource, locale and msgid dependencies
             depsItem = DependencyItem(classId, "", "|dependency.json|")
             depsItem.isLoadDep = category == "load"
             result[category].append(depsItem)
     return result
Ejemplo n.º 4
0
 def depsItems_from_Json(self, deps_json):
     result = {'run':[], 'load':[], 'ignore':[]}
     for category in ('run', 'load'):
         for classId in deps_json[category]:
             if any([classId.startswith(x) for x in ('/resource/', '/translation/', '/locale/')]):
                 continue  # sorting out resource, locale and msgid dependencies
             depsItem = DependencyItem(classId, '', '|dependency.json|')
             depsItem.isLoadDep = category == 'load'
             result[category].append(depsItem)
     return result
Ejemplo n.º 5
0
 def depsItems_from_Json(self, deps_json):
     result = {'run':[], 'load':[], 'ignore':[]}
     for category in ('run', 'load'):
         for classId in deps_json[category]:
             if any([classId.startswith(x) for x in ('/resource/', '/translation/', '/locale/')]):
                 continue  # sorting out resource, locale and msgid dependencies
             depsItem = DependencyItem(classId, '', '|dependency.json|')
             depsItem.isLoadDep = category == 'load'
             result[category].append(depsItem)
     return result
Ejemplo n.º 6
0
    def dependencies_from_comphints(self, node):
        load, run = [], []
        # Read meta data
        meta = self.getHints()
        metaLoad = meta.get("loadtimeDeps", [])
        metaRun = meta.get("runtimeDeps", [])
        metaOptional = meta.get("optionalDeps", [])
        metaIgnore = meta.get("ignoreDeps", [])
        metaIgnore.extend(metaOptional)
        all_feature_checks = [False,
                              False]  # load_feature_checks, run_feature_checks

        # regexify globs in metaignore
        metaIgnore = map(HintArgument, metaIgnore)

        # Turn strings into DependencyItems()
        for target, metaHint in ((load, metaLoad), (run, metaRun)):
            for key in metaHint:
                # add all feature checks if requested
                if key == "feature-checks":
                    all_feature_checks[bool(metaHint == metaRun)] = True
                    target.extend(
                        self.depsItems_from_envchecks(-1,
                                                      metaHint == metaLoad))
                # turn an entry into a DependencyItem
                elif isinstance(key, types.StringTypes):
                    sig = key.split('#', 1)
                    className = sig[0]
                    attrName = sig[1] if len(sig) > 1 else ''
                    target.append(
                        DependencyItem(className, attrName, self.id,
                                       "|hints|"))

        # Add JSDoc Hints
        for hint in node.hint.iterator():
            for target, hintKey in ((load, 'require'), (run, 'use')):
                if hintKey in hint.hints:
                    for hintArg in hint.hints[hintKey][None]:
                        # add all feature checks if requested
                        if hintArg == "feature-checks":
                            all_feature_checks[bool(hintKey == 'use')] = True
                            target.extend(
                                self.depsItems_from_envchecks(
                                    hint.node.get('line', -1),
                                    metaHint == metaLoad))
                        # turn the HintArgument into a DependencyItem
                        else:
                            sig = hintArg.source.split('#', 1)
                            className = sig[0]
                            attrName = sig[1] if len(sig) > 1 else ''
                            target.append(
                                DependencyItem(className, attrName, self.id,
                                               hint.node.get('line', -1)))

        return load, run, metaIgnore, all_feature_checks
Ejemplo n.º 7
0
    def getCombinedDeps(self, classesAll_, variants, config, stripSelfReferences=True, projectClassNames=True, genProxy=None, force=False, tree=None):

        # init lists
        global ClassesAll
        ClassesAll = classesAll_  # TODO: this is a quick hack, to not have to pass classesAll_ around as param
        loadFinal = []
        runFinal  = []

        # add static dependencies
        if genProxy == None:
            static, cached = self.dependencies (variants, force, tree=tree)
        else:
            static, cached = genProxy.dependencies(self.id, self.path, variants)

        loadFinal.extend(static["load"])
        runFinal.extend(static["run"])

        # fix self-references
        if stripSelfReferences:
            loadFinal = [x for x in loadFinal if x.name != self.id]
            runFinal  = [x for x in runFinal  if x.name != self.id]

        # collapse multiple occurrences of the same class
        if projectClassNames:
            def dedup(deps):
                out = []
                seen = set()
                for dep in deps:
                    name = dep.name
                    if name in seen:
                        continue
                    seen.add(name)
                    out.append(dep)
                return out

            loadFinal = dedup(loadFinal)
            runFinal = dedup(runFinal)

        # add config dependencies
        crequire = config.get("require", {})
        if self.id in crequire:
            loadFinal.extend(DependencyItem(x, '', "|config|") for x in crequire[self.id])

        cuse = config.get("use", {})
        if self.id in cuse:
            runFinal.extend(DependencyItem(x, '', "|config|") for x in cuse[self.id])

        # result dict
        deps = {
            "load"   : loadFinal,
            "run"    : runFinal,
            "ignore" : static['ignore'],
        }

        return deps, cached
Ejemplo n.º 8
0
    def _analyzeClassDepsNode_2(self,
                                node,
                                depsList,
                                inLoadContext,
                                inDefer=False):
        if node.type in ('file', 'function', 'catch'):
            top_scope = node.scope
        else:
            top_scope = scopes.find_enclosing(
                node)  # get enclosing scope of node
        for scope in top_scope.scope_iterator(
        ):  # walk through this and all nested scopes
            for global_name, scopeVar in scope.globals().items(
            ):  # get the global symbols { sym_name: ScopeVar }
                for var_node in scopeVar.uses:  # create a depsItem for all its uses
                    if treeutil.hasAncestor(
                            var_node, node
                    ):  # var_node is not disconnected through optimization
                        depsItem = self.qualify_deps_item(
                            var_node, scope.is_load_time, scope.is_defer)
                        # as this also does filtering
                        if depsItem:
                            depsList.append(depsItem)  # and qualify them
                            #if depsItem.name == "qx.log.appender.Console":
                            #    import pydb; pydb.debugger()

        # Augment with feature dependencies introduces with qx.core.Environment.get("...") calls
        for env_operand in variantoptimizer.findVariantNodes(node):
            call_node = env_operand.parent.parent
            env_key = call_node.getChild("arguments").children[0].get(
                "value", "")
            className, classAttribute = self.getClassNameFromEnvKey(env_key)
            if className:
                #print className
                depsItem = DependencyItem(className, classAttribute, self.id,
                                          env_operand.get('line', -1))
                depsItem.isCall = True  # treat as if actual call, to collect recursive deps
                # .inLoadContext
                # get 'qx' node of 'qx.core.Environment....'
                qx_idnode = treeutil.findFirstChainChild(env_operand)
                scope = qx_idnode.scope
                inLoadContext = scope.is_load_time  # get its scope's .is_load_time
                depsItem.isLoadDep = inLoadContext
                if inLoadContext:
                    depsItem.needsRecursion = True
                depsList.append(depsItem)

        return
Ejemplo n.º 9
0
 def visit_call(self, node):
     #print "visiting", node.type
     if variantoptimizer.isEnvironmentCall(node):
         assert self.opts.envmappings
         key = treeutil.selectNode(node, "arguments/1")
         classname, methname = self.getClassNameFromEnvKey(key, self.opts.envmappings)
         if classname:
             depsItem = DependencyItem(classname, methname, self.file_name, 
                                       node.get('line',0) or -1)
             depsItem.isCall = True  # treat as if actual call, to collect recursive deps
             # check phase
             functor = node.getChild("operand")  # get the "qx.core.Environment" symbol
             if self.is_static_loaddep(functor):
                 depsItem.isLoadDep = True
                 depsItem.needsRecursion = True
             self.deps.append(depsItem)
Ejemplo n.º 10
0
 def getAllEnvChecks(self, nodeline, inLoadContext):
     result = []
     envmappings = self.context['envchecksmap']
     for key in envmappings:
         clsname, clsattribute = self.getClassNameFromEnvKey(key)
         result.append(DependencyItem(clsname, clsattribute, self.id, nodeline, inLoadContext))
     return result
Ejemplo n.º 11
0
 def depsItems_from_envchecks(self, nodeline, inLoadContext):
     # Without qx.core.Environment._checksMap:
     # ---------------------------------------
     result = []
     qcEnvClass = ClassesAll['qx.core.Environment']
     for key in qcEnvClass.envKeyProviderIndex:
         clsname = qcEnvClass.classNameFromEnvKeyByIndex(key)
         result.append(DependencyItem(clsname, "", self.id, nodeline, inLoadContext))
     return result
Ejemplo n.º 12
0
    def depsItem_from_node(self, full_name, var_node):
        # attribute (e.g. method)
        attribute = ''
        # requestor (class id of the current tree)
        requestor = self.file_name
        # line (where requested)
        line = var_node.get("line",False) or -1
        # is it a static load-time dependency?
        isLoadDep = self.is_static_loaddep(var_node)

        depsItem = DependencyItem(full_name, attribute, requestor, line, isLoadDep)

        # is the var a call operand
        var_root = treeutil.findChainRoot(var_node)
        depsItem.isCall = var_root.hasParentContext("call/operand")
        # depsItem.needsRecursion can only be set in transitive analysis

        return depsItem
Ejemplo n.º 13
0
 def visit_call(self, node):
     #print "visiting", node.type
     if variantoptimizer.isEnvironmentCall(node):
         assert self.opts.envmappings
         key = treeutil.selectNode(node, "arguments/1")
         classname, methname = self.getClassNameFromEnvKey(
             key, self.opts.envmappings)
         if classname:
             depsItem = DependencyItem(classname, methname, self.file_name,
                                       node.get('line', 0) or -1)
             depsItem.isCall = True  # treat as if actual call, to collect recursive deps
             # check phase
             functor = node.getChild(
                 "operand")  # get the "qx.core.Environment" symbol
             if self.is_static_loaddep(functor):
                 depsItem.isLoadDep = True
                 depsItem.needsRecursion = True
             self.deps.append(depsItem)
Ejemplo n.º 14
0
 def depsItems_from_envchecks(self, nodeline, inLoadContext):
     result = []
     qcEnvClass = ClassesAll['qx.core.Environment']
     for key in qcEnvClass.checksMap:
         clsname, clsattribute = qcEnvClass.classNameFromEnvKey(key)
         result.append(
             DependencyItem(clsname, clsattribute, self.id, nodeline,
                            inLoadContext))
     return result
 def dependencies_from_envcalls(self, node):
     depsList = []
     qcEnvClass = ClassesAll['qx.core.Environment']
     for env_operand in variantoptimizer.findVariantNodes(node):
         call_node = env_operand.parent.parent
         env_key = call_node.getChild("arguments").children[0].get("value", "")
         className, classAttribute = qcEnvClass.classNameFromEnvKey(env_key)
         if className and className in ClassesAll:
             #print className
             depsItem = DependencyItem(className, classAttribute, self.id, env_operand.get('line', -1))
             depsItem.isCall = True  # treat as if actual call, to collect recursive deps
             # .inLoadContext
             qx_idnode = treeutil.findFirstChainChild(env_operand) # 'qx' node of 'qx.core.Environment....'
             scope = qx_idnode.scope
             depsItem.isLoadDep = scope.is_load_time
             if depsItem.isLoadDep:
                 depsItem.needsRecursion = True
             depsList.append(depsItem)
     return depsList
Ejemplo n.º 16
0
    def depsItem_from_node(self, full_name, var_node):
        # attribute (e.g. method)
        attribute = ''
        # requestor (class id of the current tree)
        requestor = self.file_name
        # line (where requested)
        line = var_node.get("line", False) or -1
        # is it a static load-time dependency?
        isLoadDep = self.is_static_loaddep(var_node)

        depsItem = DependencyItem(full_name, attribute, requestor, line,
                                  isLoadDep)

        # is the var a call operand
        var_root = treeutil.findChainRoot(var_node)
        depsItem.isCall = var_root.hasParentContext("call/operand")
        # depsItem.needsRecursion can only be set in transitive analysis

        return depsItem
Ejemplo n.º 17
0
        def buildShallowDeps(tree=None):

            load, run   = [], []
            ignore = [DependencyItem(x, '', "|DefaultIgnoredNamesDynamic|") for x in self.defaultIgnoredNamesDynamic]

            console.debug("Getting shallow deps of: %s" % self.id)
            console.indent()

            # Read source tree data
            if not tree:
                if variantSet: # a filled variantSet map means that "variants" optimization is wanted
                    tree = self.optimize(None, ["variants"], variantSet)
                else:
                    tree = self.tree()

            # Get deps from compiler hints
            if not hasattr(tree, 'hint'):
                tree = jshints.create_hints_tree(tree) # this will be used by some of the subsequent method calls
            load_hints, run_hints, ignore_hints, all_feature_checks = self.dependencies_from_comphints(tree) # ignore_hints=[HintArgument]
            load.extend(load_hints)
            run.extend(run_hints)
            load_feature_checks = all_feature_checks[0]
            run_feature_checks = all_feature_checks[1]

            # Analyze tree
            treeDeps  = []  # will be filled by _analyzeClassDepsNode
            self._analyzeClassDepsNode(tree, treeDeps, inLoadContext=True)

            # Filter lexical deps through ignore_hints
            load1, run1, ignore1 = self.filter_symbols_by_comphints(treeDeps, ignore_hints)
                # load and run are being filtered, ignore contains the actually filtered depsItems

            # integrate into existing lists
            load_hint_names = [str(x) for x in load_hints]
            for dep in load1:
                if str(dep) in load_hint_names and not load_feature_checks:
                    console.warn("%s: @require(%s) is auto-detected" % (self.id, dep))
                load.append(dep)
            run_hint_names = [str(x) for x in run_hints]
            for dep in run1:
                if str(dep) in run_hint_names and not run_feature_checks:
                    console.warn("%s: @use(%s) is auto-detected" % (self.id, dep))
                run.append(dep)
            ignore.extend(ignore1)

            console.outdent()

            # Build data structure
            deps = {
                "load"   : load,
                "run"    : run,
                "ignore" : ignore,
            }

            return deps
Ejemplo n.º 18
0
    def dependencies_from_envcalls(self, node):

        depsList = []
        if 'qx.core.Environment' not in ClassesAll:
            self.context['console'].warn("No qx.core.Environment available to extract feature keys from")
            return depsList
        qcEnvClass = ClassesAll['qx.core.Environment']

        for env_operand in variantoptimizer.findVariantNodes(node):
            call_node = env_operand.parent.parent
            env_key = call_node.getChild("arguments").children[0].get("value", "")
            # Without qx.core.Environment._checksMap:
            # ---------------------------------------
            className = qcEnvClass.classNameFromEnvKeyByIndex(env_key)
            if className and className in ClassesAll:
                #print className
                depsItem = DependencyItem(className, "", self.id, env_operand.get('line', -1))
                depsItem.isCall = True  # treat as if actual call, to collect recursive deps
                depsItem.node = call_node
                # .inLoadContext
                qx_idnode = treeutil.findFirstChainChild(env_operand) # 'qx' node of 'qx.core.Environment....'
                scope = qx_idnode.scope
                depsItem.isLoadDep = scope.is_load_time
                if depsItem.isLoadDep:
                    depsItem.needsRecursion = True
                depsList.append(depsItem)
            # With qx.core.Environment._checksMap:
            # ------------------------------------
            # className, classAttribute = qcEnvClass.classNameFromEnvKey(env_key)
            # if className and className in ClassesAll:
            #     #print className
            #     depsItem = DependencyItem(className, classAttribute, self.id, env_operand.get('line', -1))
            #     depsItem.isCall = True  # treat as if actual call, to collect recursive deps
            #     depsItem.node = call_node
            #     # .inLoadContext
            #     qx_idnode = treeutil.findFirstChainChild(env_operand) # 'qx' node of 'qx.core.Environment....'
            #     scope = qx_idnode.scope
            #     depsItem.isLoadDep = scope.is_load_time
            #     if depsItem.isLoadDep:
            #         depsItem.needsRecursion = True
            #     depsList.append(depsItem)
        return depsList
Ejemplo n.º 19
0
 def dependencies_from_envcalls(self, node):
     depsList = []
     if 'qx.core.Environment' not in ClassesAll:
         self.context['console'].warn(
             "No qx.core.Environment available to extract feature keys from"
         )
         return depsList
     qcEnvClass = ClassesAll['qx.core.Environment']
     for env_operand in variantoptimizer.findVariantNodes(node):
         call_node = env_operand.parent.parent
         env_key = call_node.getChild("arguments").children[0].get(
             "value", "")
         className, classAttribute = qcEnvClass.classNameFromEnvKey(env_key)
         if className and className in ClassesAll:
             #print className
             depsItem = DependencyItem(className, classAttribute, self.id,
                                       env_operand.get('line', -1))
             depsItem.isCall = True  # treat as if actual call, to collect recursive deps
             depsItem.node = call_node
             # .inLoadContext
             qx_idnode = treeutil.findFirstChainChild(
                 env_operand)  # 'qx' node of 'qx.core.Environment....'
             scope = qx_idnode.scope
             depsItem.isLoadDep = scope.is_load_time
             if depsItem.isLoadDep:
                 depsItem.needsRecursion = True
             depsList.append(depsItem)
     return depsList
Ejemplo n.º 20
0
    def _analyzeClassDepsNode_2(self, node, depsList, inLoadContext, inDefer=False):
        if node.type in ('file', 'function', 'catch'):
            top_scope = node.scope
        else:
            top_scope = scopes.find_enclosing(node)  # get enclosing scope of node
        for scope in top_scope.scope_iterator(): # walk through this and all nested scopes
            for global_name, scopeVar in scope.globals().items():  # get the global symbols { sym_name: ScopeVar }
                for var_node in scopeVar.uses:       # create a depsItem for all its uses
                    if treeutil.hasAncestor(var_node, node): # var_node is not disconnected through optimization
                        depsItem = self.qualify_deps_item(var_node, scope.is_load_time, scope.is_defer)
                        # as this also does filtering
                        if depsItem:
                            depsList.append(depsItem)    # and qualify them
                            #if depsItem.name == "qx.log.appender.Console":
                            #    import pydb; pydb.debugger()

        # Augment with feature dependencies introduces with qx.core.Environment.get("...") calls
        for env_operand in variantoptimizer.findVariantNodes(node):
            call_node = env_operand.parent.parent
            env_key = call_node.getChild("arguments").children[0].get("value", "")
            className, classAttribute = self.getClassNameFromEnvKey(env_key)
            if className:
                #print className
                depsItem = DependencyItem(className, classAttribute, self.id, env_operand.get('line', -1))
                depsItem.isCall = True  # treat as if actual call, to collect recursive deps
                # .inLoadContext
                # get 'qx' node of 'qx.core.Environment....'
                qx_idnode = treeutil.findFirstChainChild(env_operand)
                scope = qx_idnode.scope
                inLoadContext = scope.is_load_time # get its scope's .is_load_time
                depsItem.isLoadDep = inLoadContext
                if inLoadContext:
                    depsItem.needsRecursion = True
                depsList.append(depsItem)

        return
Ejemplo n.º 21
0
    def depsItem_from_node(self, node):
        scope = node.scope
        # some initializations (might get refined later)
        depsItem = DependencyItem('', '', '')
        depsItem.name           = ''
        depsItem.attribute      = ''
        depsItem.requestor      = self.id
        depsItem.line           = node.get("line", -1)
        depsItem.isLoadDep      = scope.is_load_time
        depsItem.needsRecursion = False
        depsItem.isCall         = False
        depsItem.node           = node
        is_lib_class             = False
        var_root = treeutil.findVarRoot(node)  # various of the tests need the var (dot) root, rather than the head symbol (like 'qx')

        # .isCall
        if treeutil.isCallOperand(var_root): # it's a function call or new op.
            depsItem.isCall = True  # interesting when following transitive deps

        # .name, .attribute
        assembled = (treeutil.assembleVariable(node))[0]
        className, classAttribute = self._splitQxClass(assembled)
        assembled_parts = assembled.split('.')
        if not className: 
            if "." in assembled:
                className = '.'.join(assembled_parts[:-1])
                classAttribute = assembled_parts[-1]
                #className, classAttribute = assembled.split('.')[:2]
            else:
                className = assembled
        else:
            is_lib_class = True
        # we allow self-references, to be able to track method dependencies within the same class
        if assembled_parts[0] == 'this':
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        elif scope.is_defer and assembled_parts[0] in DEFER_ARGS:
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        if is_lib_class and not classAttribute:  # see if we have to provide 'construct'
            if treeutil.isNEWoperand(var_root):
                classAttribute = 'construct'
        depsItem.name = className
        depsItem.attribute = classAttribute

        # .needsRecursion
        # Mark items that need recursive analysis of their dependencies (bug#1455)
        #if self.followCallDeps(var_root, self.id, className, isLoadTime):
        #if self.id=='qx.bom.element.Style' and depsItem.attribute=='__detectVendorProperties':
        #    import pydb; pydb.debugger()
        if (is_lib_class and
            scope.is_load_time and
            (treeutil.isCallOperand(var_root) or 
             treeutil.isNEWoperand(var_root))):
            depsItem.needsRecursion = True

        return depsItem
Ejemplo n.º 22
0
    def qualify_deps_item(self, node, isLoadTime, inDefer, depsItem=None):
        if not depsItem:
            depsItem = DependencyItem('', '', '')
        depsItem.name = ''
        depsItem.attribute = ''
        depsItem.requestor = self.id
        depsItem.line = node.get("line", -1)
        depsItem.isLoadDep = isLoadTime
        depsItem.needsRecursion = False
        depsItem.isCall = False
        var_root = treeutil.findVarRoot(node)  # various of the tests need the var (dot) root, rather than the head symbol (like 'qx')

        # .isCall
        if var_root.hasParentContext("call/operand"): # it's a function call
            depsItem.isCall = True  # interesting when following transitive deps

        # .name
        assembled = (treeutil.assembleVariable(node))[0]
        _, className, classAttribute = self._isInterestingReference(assembled, var_root, self.id, inDefer)
        # postcond: 
        # - className != '' must always be true, as we know it is an interesting reference
        # - might be a known qooxdoo class, or an unknown class (use 'className in self._classes')
        # - if assembled contained ".", classAttribute will contain approx. non-class part

        if className:
            # we allow self-references, to be able to track method dependencies within the same class
            if className == 'this':
                className = self.id
            elif inDefer and className in DEFER_ARGS:
                className = self.id
            if not classAttribute:  # see if we have to provide 'construct'
                if treeutil.isNEWoperand(node):
                    classAttribute = 'construct'
            # Can't do the next; it's catching too many occurrences of 'getInstance' that have
            # nothing to do with the singleton 'getInstance' method (just grep in the framework)
            #elif classAttribute == 'getInstance':  # erase 'getInstance' and introduce 'construct' dependency
            #    classAttribute = 'construct'
            depsItem.name = className
            depsItem.attribute = classAttribute

            # .needsRecursion
            # Mark items that need recursive analysis of their dependencies (bug#1455)
            if self.followCallDeps(var_root, self.id, className, isLoadTime):
                depsItem.needsRecursion = True

        if depsItem.name:
            return depsItem
        else:
            return None
Ejemplo n.º 23
0
        def buildShallowDeps(tree=None):

            load   = []
            run    = []
            ignore = [DependencyItem(x, '', "|DefaultIgnoredNamesDynamic|") for x in self.defaultIgnoredNamesDynamic]

            console.debug("Analyzing tree: %s" % self.id)
            console.indent()

            # Read meta data
            meta         = self.getHints()
            metaLoad     = meta.get("loadtimeDeps", [])
            metaRun      = meta.get("runtimeDeps" , [])
            metaOptional = meta.get("optionalDeps", [])
            metaIgnore   = meta.get("ignoreDeps"  , [])
            metaIgnore.extend(metaOptional)

            # regexify globs in metaignore
            metaIgnore = map(MetaIgnore, metaIgnore)

            # Turn strings into DependencyItems()
            for target,metaHint in ((load,metaLoad), (run,metaRun), (ignore,metaIgnore)):
                for key in metaHint:
                    # add all feature checks if requested
                    if key == "feature-checks" and metaHint in (metaLoad, metaRun):
                        target.extend(self.getAllEnvChecks(-1, metaHint==metaLoad))
                    # turn an entry into a DependencyItem
                    elif isinstance(key, types.StringTypes):
                        sig = key.split('#',1)
                        className = sig[0]
                        attrName  = sig[1] if len(sig)>1 else ''
                        target.append(DependencyItem(className, attrName, self.id, "|hints|"))

            # Read source tree data
            if not tree:
                if variantSet: # a filled variantSet map means that "variants" optimization is wanted
                    tree = self.optimize(None, ["variants"], variantSet)
                else:
                    tree = self.tree()

            # analyze tree
            treeDeps  = []  # will be filled by _analyzeClassDepsNode
            self._analyzeClassDepsNode(tree, treeDeps, inLoadContext=True)

            # Process source tree data
            for dep in treeDeps:
                if dep.isLoadDep:
                    if "auto-require" not in metaIgnore:
                        item = dep.name
                        if item in metaIgnore:
                            pass
                        elif item in metaLoad:
                            console.warn("%s: #require(%s) is auto-detected" % (self.id, item))
                        else:
                            # adding all items to list (the second might have needsRecursion)
                            load.append(dep)

                else: # runDep
                    if "auto-use" not in metaIgnore:
                        item = dep.name
                        if item in metaIgnore:
                            pass
                        #elif item in (x.name for x in load):
                        #    pass
                        elif item in metaRun:
                            console.warn("%s: #use(%s) is auto-detected" % (self.id, item))
                        else:
                            # adding all items to list (to comply with the 'load' deps)
                            run.append(dep)

            console.outdent()

            # Build data structure
            deps = {
                "load"   : load,
                "run"    : run,
                "ignore" : ignore,
            }

            return deps
Ejemplo n.º 24
0
    def _analyzeClassDepsNode_1(self,
                                node,
                                depsList,
                                inLoadContext,
                                inDefer=False):

        if node.isVar():
            if node.dep:
                depsList.append(node.dep)
                return

            assembled = (treeutil.assembleVariable(node))[0]

            # treat dependencies in defer as requires
            deferNode = self.checkDeferNode(assembled, node)
            if deferNode != None:
                self._analyzeClassDepsNode(deferNode,
                                           depsList,
                                           inLoadContext=True,
                                           inDefer=True)

            (context, className,
             classAttribute) = self._isInterestingReference(
                 assembled, node, self.id, inDefer)
            # postcond:
            # - if className != '' it is an interesting reference
            # - might be a known qooxdoo class, or an unknown class (use 'className in self._classes')
            # - if assembled contained ".", classAttribute will contain approx. non-class part

            if className:
                # we allow self-references, to be able to track method dependencies within the same class
                if className == 'this':
                    className = self.id
                elif inDefer and className in DEFER_ARGS:
                    className = self.id
                if not classAttribute:  # see if we have to provide 'construct'
                    if treeutil.isNEWoperand(node):
                        classAttribute = 'construct'
                # Can't do the next; it's catching too many occurrences of 'getInstance' that have
                # nothing to do with the singleton 'getInstance' method (just grep in the framework)
                #elif classAttribute == 'getInstance':  # erase 'getInstance' and introduce 'construct' dependency
                #    classAttribute = 'construct'
                line = node.get('line', 0)
                depsItem = DependencyItem(className, classAttribute, self.id,
                                          line if line else -1, inLoadContext)
                #print "-- adding: %s (%s:%s)" % (className, treeutil.getFileFromSyntaxItem(node), node.get('line',False))
                if node.hasParentContext(
                        "call/operand"):  # it's a function call
                    depsItem.isCall = True  # interesting when following transitive deps

                # Adding all items to list; let caller sort things out
                depsList.append(depsItem)
                node.dep = depsItem

                # Mark items that need recursive analysis of their dependencies (bug#1455)
                if self.followCallDeps(node, self.id, className,
                                       inLoadContext):
                    depsItem.needsRecursion = True

        # check e.g. qx.core.Environment.get("runtime.name")
        elif node.type == "constant" and node.hasParentContext(
                "call/arguments"):
            if node.dep:
                depsList.append(node.dep)
                return
            callnode = treeutil.selectNode(node, "../..")
            if variantoptimizer.isEnvironmentCall(callnode):
                className, classAttribute = self.getClassNameFromEnvKey(
                    node.get("value", ""))
                if className:
                    depsItem = DependencyItem(className,
                                              classAttribute, self.id,
                                              node.get('line',
                                                       -1), inLoadContext)
                    depsItem.isCall = True  # treat as if actual call, to collect recursive deps
                    if inLoadContext:
                        depsItem.needsRecursion = True
                    depsList.append(depsItem)
                    node.dep = depsItem

        elif node.type == "body" and node.parent.type == "function":
            if (node.parent.hasParentContext("call/operand")
                    or node.parent.hasParentContext("call/operand/group")):
                # if the function is immediately called, it's still load context (if that's what it was before)
                pass
            else:
                inLoadContext = False

        if node.hasChildren():
            for child in node.children:
                self._analyzeClassDepsNode(child, depsList, inLoadContext,
                                           inDefer)

        return
Ejemplo n.º 25
0
            # because all classes are included like an explicit include.
            for classId in excludeWithDeps:
                result.remove(classId)

        # Calculate dependencies
        else:
            #self._console.info(" ", feed=False)

            # Multiple loop over class list calculation
            processedEnvironment = False
            result      = []          # reset any previous results for this iteration
            resultNames = []

            # calculate class list recursively
            for item in includeWithDeps:
                depsItem = DependencyItem(item, '', '|config|')
                # calculate dependencies and add required classes
                classlistFromClassRecursive(depsItem, excludeWithDeps, variants, result, warn_deps, [], allowBlockLoaddeps)
                #classlistFromClassIterative(depsItem, excludeWithDeps, variants, result, warn_deps, [], allowBlockLoaddeps)

            self._console.dotclear()
                    
            if self._console.getLevel() is "info":
                #self._console.nl()
                pass

            # extract names of depsItems
            result = [x.name for x in result]

        # warn about unknown references
        # add the list of name spaces of the selected classes
Ejemplo n.º 26
0
        def getTransitiveDepsR(dependencyItem, variantString, totalDeps):

            # We don't add the in-param to the global result
            classId  = dependencyItem.name
            methodId = dependencyItem.attribute
            function_pruned = False

            cacheId = "methoddeps-%r-%r-%r" % (classId, methodId, variantString)
                # The bad thing here is that 'variantString' contains environment setting
                # that normally have no influence on the dependencies (like
                # 'qx.Application'). So cached deps are rejected for no reason (ex.
                # building the demos of Demobrowser). But I cannot easily apply
                # variant-projection here, as it only proves that the current class is
                # independent of a specific environement key; but its recursive deps could
                # well be. Fix: Get the shallow deps of the current method from cache, and then get the
                # trans. deps of those items. They then could appy the same reasoning.
            if not force:
                # Check cache
                cachedDeps, _ = cache.read(cacheId)  # no use to put this into a file, due to transitive dependencies to other files
                if cachedDeps != None:
                    console.debug("using cached result")
                    #print "\nusing cached result for", classId, methodId
                    return cachedDeps

            # Need to calculate deps
            console.dot(1)

            # Check known class
            if classId not in ClassesAll:
                console.debug("Skipping unknown class of dependency: %s#%s (%s:%d)" % (classId, methodId,
                              dependencyItem.requestor, dependencyItem.line))
                return set()

            # Check other class
            elif classId != self.id:
                classObj = ClassesAll[classId]
                otherdeps = classObj.getTransitiveDeps(dependencyItem, variants, classMaps, totalDeps, force)
                return otherdeps

            # Check own hierarchy
            defClassId, attribNode = self.findClassForFeature(methodId, variants, classMaps)

            # lookup error
            if not defClassId or defClassId not in ClassesAll:
                console.debug("Skipping unknown definition of dependency: %s#%s (%s:%d)" % (classId,
                              methodId, dependencyItem.requestor, dependencyItem.line))
                return set()

            defDepsItem = DependencyItem(defClassId, methodId, classId)
            if dependencyItem.isCall:
                defDepsItem.isCall = True  # if the dep is an inherited method being called, pursue the parent method as call
            localDeps   = set()

            # inherited feature
            if defClassId != classId:
                self.resultAdd(defDepsItem, localDeps)
                defClass = ClassesAll[defClassId]
                otherdeps = defClass.getTransitiveDeps(defDepsItem, variants, classMaps, totalDeps, force)
                localDeps.update(otherdeps)
                return localDeps

            # Process own deps
            console.debug("%s#%s dependencies:" % (classId, methodId))
            console.indent()

            if isinstance(attribNode, Node):

                if (attribNode.getChild("function", False)       # is it a function(){..} value?
                    and not dependencyItem.isCall                # and the reference was no call
                   ):
                    function_pruned = True
                    pass                                         # don't lift those deps
                else:
                    # Get the method's immediate deps
                    # TODO: is this the right API?!
                    depslist = []
                    if attribNode.type == 'value':
                       attribNode = attribNode.children[0]
                    self._analyzeClassDepsNode(attribNode, depslist, inLoadContext=False)
                    console.debug( "shallow dependencies: %r" % (depslist,))

                    # This depends on attribNode belonging to current class
                    my_ignores = self.getHints("ignoreDeps") + self.getHints("optionalDeps")
                    my_ignores = map(HintArgument, my_ignores)

                    for depsItem in depslist:
                        if depsItem in totalDeps:
                            continue
                        if depsItem.name in my_ignores:
                            continue
                        if self.resultAdd(depsItem, localDeps):
                            totalDeps = totalDeps.union(localDeps)
                            # Recurse dependencies
                            downstreamDeps = getTransitiveDepsR(depsItem, variants, totalDeps)
                            localDeps.update(downstreamDeps)

            # Cache update
            # ---   i cannot cache currently, if the deps of a function are pruned
            #       when the function is passed as a ref, rather than called (s. above
            #       around 'attribNode.getChild("function",...)')
            if not function_pruned:
                cache.write(cacheId, localDeps, memory=True, writeToFile=False)

            console.outdent()
            return localDeps
Ejemplo n.º 27
0
    def qualify_deps_item(self, node, isLoadTime, inDefer, depsItem=None):
        if not depsItem:
            depsItem = DependencyItem('', '', '')
        depsItem.name = ''
        depsItem.attribute = ''
        depsItem.requestor = self.id
        depsItem.line = node.get("line", -1)
        depsItem.isLoadDep = isLoadTime
        depsItem.needsRecursion = False
        depsItem.isCall = False
        var_root = treeutil.findVarRoot(
            node
        )  # various of the tests need the var (dot) root, rather than the head symbol (like 'qx')

        # .isCall
        if var_root.hasParentContext("call/operand"):  # it's a function call
            depsItem.isCall = True  # interesting when following transitive deps

        # .name
        assembled = (treeutil.assembleVariable(node))[0]
        _, className, classAttribute = self._isInterestingReference(
            assembled, var_root, self.id, inDefer)
        # postcond:
        # - className != '' must always be true, as we know it is an interesting reference
        # - might be a known qooxdoo class, or an unknown class (use 'className in self._classes')
        # - if assembled contained ".", classAttribute will contain approx. non-class part

        if className:
            # we allow self-references, to be able to track method dependencies within the same class
            if className == 'this':
                className = self.id
            elif inDefer and className in DEFER_ARGS:
                className = self.id
            if not classAttribute:  # see if we have to provide 'construct'
                if treeutil.isNEWoperand(node):
                    classAttribute = 'construct'
            # Can't do the next; it's catching too many occurrences of 'getInstance' that have
            # nothing to do with the singleton 'getInstance' method (just grep in the framework)
            #elif classAttribute == 'getInstance':  # erase 'getInstance' and introduce 'construct' dependency
            #    classAttribute = 'construct'
            depsItem.name = className
            depsItem.attribute = classAttribute

            # .needsRecursion
            # Mark items that need recursive analysis of their dependencies (bug#1455)
            if self.followCallDeps(var_root, self.id, className, isLoadTime):
                depsItem.needsRecursion = True

        if depsItem.name:
            return depsItem
        else:
            return None
Ejemplo n.º 28
0
        def buildShallowDeps(tree=None):

            load = []
            run = []
            ignore = [
                DependencyItem(x, '', "|DefaultIgnoredNamesDynamic|")
                for x in self.defaultIgnoredNamesDynamic
            ]

            console.debug("Analyzing tree: %s" % self.id)
            console.indent()

            # Read meta data
            meta = self.getHints()
            metaLoad = meta.get("loadtimeDeps", [])
            metaRun = meta.get("runtimeDeps", [])
            metaOptional = meta.get("optionalDeps", [])
            metaIgnore = meta.get("ignoreDeps", [])
            metaIgnore.extend(metaOptional)

            # regexify globs in metaignore
            metaIgnore = map(MetaIgnore, metaIgnore)

            # Turn strings into DependencyItems()
            for target, metaHint in ((load, metaLoad), (run, metaRun),
                                     (ignore, metaIgnore)):
                for key in metaHint:
                    # add all feature checks if requested
                    if key == "feature-checks" and metaHint in (metaLoad,
                                                                metaRun):
                        target.extend(
                            self.getAllEnvChecks(-1, metaHint == metaLoad))
                    # turn an entry into a DependencyItem
                    elif isinstance(key, types.StringTypes):
                        sig = key.split('#', 1)
                        className = sig[0]
                        attrName = sig[1] if len(sig) > 1 else ''
                        target.append(
                            DependencyItem(className, attrName, self.id,
                                           "|hints|"))

            # Read source tree data
            if not tree:
                if variantSet:  # a filled variantSet map means that "variants" optimization is wanted
                    tree = self.optimize(None, ["variants"], variantSet)
                else:
                    tree = self.tree()

            # do lint checking here, as we have a classList ("ClassesAll") to check globals against
            if True:
                # construct parse-level lint options
                opts = lint.defaultOptions()
                opts.library_classes = ClassesAll.keys()
                opts.class_namespaces = ClassList.namespaces_from_classnames(
                    opts.library_classes)
                # some sensible settings (deviating from defaultOptions)
                opts.ignore_no_loop_block = True
                opts.ignore_reference_fields = True
                opts.ignore_undeclared_privates = True
                opts.ignore_unused_variables = True
                # override from config
                jobConf = Context.jobconf
                for option, value in jobConf.get("lint-check", {}).items():
                    setattr(opts, option.replace("-", "_"), value)
                lint.lint_check(tree, self.id, opts)

            # analyze tree
            treeDeps = []  # will be filled by _analyzeClassDepsNode
            self._analyzeClassDepsNode(tree, treeDeps, inLoadContext=True)

            # Process source tree data
            for dep in treeDeps:
                if dep.isLoadDep:
                    if "auto-require" not in metaIgnore:
                        item = dep.name
                        if item in metaIgnore:
                            pass
                        elif item in metaLoad:
                            console.warn("%s: #require(%s) is auto-detected" %
                                         (self.id, item))
                        else:
                            # adding all items to list (the second might have needsRecursion)
                            load.append(dep)

                else:  # runDep
                    if "auto-use" not in metaIgnore:
                        item = dep.name
                        if item in metaIgnore:
                            pass
                        #elif item in (x.name for x in load):
                        #    pass
                        elif item in metaRun:
                            console.warn("%s: #use(%s) is auto-detected" %
                                         (self.id, item))
                        else:
                            # adding all items to list (to comply with the 'load' deps)
                            run.append(dep)

            console.outdent()

            # Build data structure
            deps = {
                "load": load,
                "run": run,
                "ignore": ignore,
            }

            return deps
Ejemplo n.º 29
0
    def _analyzeClassDepsNode(self, node, depsList, inLoadContext, inDefer=False):

        if node.type == "variable":
            assembled = (treeutil.assembleVariable(node))[0]

            # treat dependencies in defer as requires
            deferNode = self.checkDeferNode(assembled, node)
            if deferNode != None:
                self._analyzeClassDepsNode(deferNode, depsList, inLoadContext=True, inDefer=True)

            (context, className, classAttribute) = self._isInterestingReference(assembled, node, self.id, inDefer)
            # postcond: 
            # - if className != '' it is an interesting reference
            # - might be a known qooxdoo class, or an unknown class (use 'className in self._classes')
            # - if assembled contained ".", classAttribute will contain approx. non-class part

            if className:
                # we allow self-references, to be able to track method dependencies within the same class
                if className == 'this':
                    className = self.id
                elif inDefer and className in DEFER_ARGS:
                    className = self.id
                if not classAttribute:  # see if we have to provide 'construct'
                    if node.hasParentContext("instantiation/*/*/operand"): # 'new ...' position
                        classAttribute = 'construct'
                # Can't do the next; it's catching too many occurrences of 'getInstance' that have
                # nothing to do with the singleton 'getInstance' method (just grep in the framework)
                #elif classAttribute == 'getInstance':  # erase 'getInstance' and introduce 'construct' dependency
                #    classAttribute = 'construct'
                depsItem = DependencyItem(className, classAttribute, self.id, node.get('line', -1), inLoadContext)
                #print "-- adding: %s (%s:%s)" % (className, treeutil.getFileFromSyntaxItem(node), node.get('line',False))
                if node.hasParentContext("call/operand"): # it's a function call
                    depsItem.isCall = True  # interesting when following transitive deps

                # Adding all items to list; let caller sort things out
                depsList.append(depsItem)

                # Mark items that need recursive analysis of their dependencies (bug#1455)
                if self.followCallDeps(node, self.id, className, inLoadContext):
                    depsItem.needsRecursion = True

        # check e.g. qx.core.Environment.get("runtime.name")
        elif node.type == "constant" and node.hasParentContext("call/params"):
            callnode = treeutil.selectNode(node, "../..")
            if variantoptimizer.isEnvironmentCall(callnode):
                className, classAttribute = self.getClassNameFromEnvKey(node.get("value", ""))
                if className:
                    depsItem = DependencyItem(className, classAttribute, self.id, node.get('line', -1), inLoadContext)
                    depsItem.isCall = True  # treat as if actual call, to collect recursive deps
                    depsList.append(depsItem)


        elif node.type == "body" and node.parent.type == "function":
            if (node.parent.hasParentContext("call/operand") 
                or node.parent.hasParentContext("call/operand/group")):
                # if the function is immediately called, it's still load context (if that's what it was before)
                pass
            else:
                inLoadContext = False

        if node.hasChildren():
            for child in node.children:
                self._analyzeClassDepsNode(child, depsList, inLoadContext, inDefer)

        return
Ejemplo n.º 30
0
    def depsItem_from_node(self, node):
        scope = node.scope
        # some initializations (might get refined later)
        depsItem = DependencyItem('', '', '')
        depsItem.name           = ''
        depsItem.attribute      = ''
        depsItem.requestor      = self.id
        depsItem.line           = node.get("line", -1)
        depsItem.isLoadDep      = scope.is_load_time
        depsItem.needsRecursion = False
        depsItem.isCall         = False
        depsItem.node           = node
        var_root = treeutil.findVarRoot(node)  # various of the tests need the var (dot) root, rather than the head symbol (like 'qx')

        # .isCall
        if treeutil.isCallOperand(var_root): # it's a function call or new op.
            depsItem.isCall = True  # interesting when following transitive deps

        # .name, .attribute
        assembled = (treeutil.assembleVariable(node))[0]
        #className, classAttribute = self._splitQxClass(assembled)
        className = gs.test_for_libsymbol(assembled, ClassesAll, []) # TODO: no namespaces!?
        if not className: 
            is_lib_class = False
            className = assembled
            classAttribute = ''
        else:
            is_lib_class = True
            if len(assembled) > len(className):
                classAttribute = assembled[len(className)+1:]
                dotidx = classAttribute.find(".") # see if classAttribute is chained too
                if dotidx > -1:
                    classAttribute = classAttribute[:dotidx]    # only use the first component
            else:
                classAttribute = ''
        # we allow self-references, to be able to track method dependencies within the same class
        assembled_parts = assembled.split('.')
        if assembled_parts[0] == 'this':
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        elif scope.is_defer and assembled_parts[0] in DEFER_ARGS:
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        if is_lib_class and not classAttribute:  # see if we have to provide 'construct'
            if treeutil.isNEWoperand(var_root):
                classAttribute = 'construct'
        depsItem.name = className
        depsItem.attribute = classAttribute

        # .needsRecursion
        # Mark items that need recursive analysis of their dependencies (bug#1455)
        if (is_lib_class and
            scope.is_load_time and
            (treeutil.isCallOperand(var_root) or 
             treeutil.isNEWoperand(var_root))):
            depsItem.needsRecursion = True

        return depsItem
Ejemplo n.º 31
0
    def depsItem_from_node(self, node):
        scope = node.scope
        # some initializations (might get refined later)
        depsItem = DependencyItem('', '', '')
        depsItem.name           = ''
        depsItem.attribute      = ''
        depsItem.requestor      = self.id
        depsItem.line           = node.get("line", -1)
        depsItem.isLoadDep      = scope.is_load_time
        depsItem.needsRecursion = False
        depsItem.isCall         = False
        depsItem.node           = node
        var_root = treeutil.findVarRoot(node)  # various of the tests need the var (dot) root, rather than the head symbol (like 'qx')

        # .isCall
        if treeutil.isCallOperand(var_root): # it's a function call or new op.
            depsItem.isCall = True  # interesting when following transitive deps

        # .name, .attribute
        assembled = (treeutil.assembleVariable(node))[0]
        className = gs.test_for_libsymbol(assembled, ClassesAll, []) # TODO: no namespaces!?
        if not className:
            is_lib_class = False
            className = assembled
            classAttribute = ''
        else:
            is_lib_class = True
            if len(assembled) > len(className):
                classAttribute = assembled[len(className)+1:]
                dotidx = classAttribute.find(".") # see if classAttribute is chained too
                if dotidx > -1:
                    classAttribute = classAttribute[:dotidx]    # only use the first component
            else:
                classAttribute = ''
        # we allow self-references, to be able to track method dependencies within the same class
        assembled_parts = assembled.split('.')
        if assembled_parts[0] == 'this':
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        elif scope.is_defer and assembled_parts[0] in DEFER_ARGS:
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        if is_lib_class and not classAttribute:  # see if we have to provide 'construct'
            if treeutil.isNEWoperand(var_root):
                classAttribute = 'construct'
        depsItem.name = className
        depsItem.attribute = classAttribute

        # .needsRecursion
        # Mark items that need recursive analysis of their dependencies (bug#1455)
        if (is_lib_class and
            scope.is_load_time and
            (treeutil.isCallOperand(var_root) or
             treeutil.isNEWoperand(var_root))):
            depsItem.needsRecursion = True

        return depsItem
Ejemplo n.º 32
0
    def getCombinedDeps_NOTUSED(self, fileId, variants, buildType="", stripSelfReferences=True, projectClassNames=True, genProxy=None):

        # init lists
        loadFinal = []
        runFinal  = []

        # add static dependencies
        classObj = self._classesObj[fileId]

        if genProxy == None:
            static, cached = classObj.dependencies (variants)
        else:
            static, cached = genProxy.dependencies(classObj.id, classObj.path, variants)

        loadFinal.extend(static["load"])
        runFinal.extend(static["run"])

        # fix self-references
        if stripSelfReferences:
            loadFinal = [x for x in loadFinal if x.name != fileId]
            runFinal  = [x for x in runFinal  if x.name != fileId]

        # collapse multiple occurrences of the same class
        if projectClassNames:
            loads = loadFinal
            loadFinal = []
            for dep in loads:
                if dep.name not in (x.name for x in loadFinal):
                    loadFinal.append(dep)
            runs = runFinal
            runFinal = []
            for dep in runs:
                if dep.name not in (x.name for x in runFinal):
                    runFinal.append(dep)

        # TODO: this should be removed, as it cannot happen anymore (source is not variant-optimized)
        # fix dependency to classes that get removed with variant optimization
        #variantSelectClasses = ("qx.core.Environment",)
        #if len(variants) and (classObj.id not in variantSelectClasses):
        #    depsUnOpt, _ = classObj.dependencies({})  # get unopt deps
        #    # this might incur extra generation if unoptimized deps
        #    # haven't computed before for this fileId
        #    for depItem in depsUnOpt["load"]:
        #        if depItem.name in variantSelectClasses and depItem.name not in [x.name for x in loadFinal]:
        #            loadFinal.append(depItem)
        #    for depItem in depsUnOpt["run"]:
        #        if depItem.name in variantSelectClasses and depItem.name not in [x.name for x in runFinal]:
        #            runFinal.append(depItem)

        # add config dependencies
        if fileId in self._require:
            loadFinal.extend(DependencyItem(x, '', "|config|") for x in self._require[fileId])

        if fileId in self._use:
            runFinal.extend(DependencyItem(x, '', "|config|") for x in self._use[fileId])

        # result dict
        deps = {
            "load"   : loadFinal,
            "run"    : runFinal,
            "ignore" : static['ignore'],
        }

        return deps, cached
Ejemplo n.º 33
0
        def getTransitiveDepsR(dependencyItem, variantString, totalDeps):

            # We don't add the in-param to the global result
            classId  = dependencyItem.name
            methodId = dependencyItem.attribute
            function_pruned = False

            cacheId = "methoddeps-%r-%r-%r" % (classId, methodId, variantString)
                # The bad thing here is that 'variantString' contains environment setting
                # that normally have no influence on the dependencies (like
                # 'qx.Application'). So cached deps are rejected for no reason (ex.
                # building the demos of Demobrowser). But I cannot easily apply
                # variant-projection here, as it only proves that the current class is
                # independent of a specific environement key; but its recursive deps could
                # well be. Fix: Get the shallow deps of the current method from cache, and then get the
                # trans. deps of those items. They then could appy the same reasoning.
            if not force:
                # Check cache
                cachedDeps, _ = cache.read(cacheId)  # no use to put this into a file, due to transitive dependencies to other files
                if cachedDeps != None:
                    console.debug("using cached result")
                    #print "\nusing cached result for", classId, methodId
                    return cachedDeps

            # Need to calculate deps
            console.dot("_")

            # Check known class
            if classId not in self._classesObj:
                console.debug("Skipping unknown class of dependency: %s#%s (%s:%d)" % (classId, methodId,
                              dependencyItem.requestor, dependencyItem.line))
                return set()

            # Check other class
            elif classId != self.id:
                classObj = self._classesObj[classId]
                otherdeps = classObj.getTransitiveDeps(dependencyItem, variants, classMaps, totalDeps, force)
                return otherdeps

            # Check own hierarchy
            defClassId, attribNode = self.findClassForFeature(methodId, variants, classMaps)

            # lookup error
            if not defClassId or defClassId not in self._classesObj:
                console.debug("Skipping unknown definition of dependency: %s#%s (%s:%d)" % (classId, 
                              methodId, dependencyItem.requestor, dependencyItem.line))
                return set()
            
            defDepsItem = DependencyItem(defClassId, methodId, classId)
            if dependencyItem.isCall:
                defDepsItem.isCall = True  # if the dep is an inherited method being called, pursue the parent method as call
            localDeps   = set()

            # inherited feature
            if defClassId != classId:
                self.resultAdd(defDepsItem, localDeps)
                defClass = self._classesObj[defClassId]
                otherdeps = defClass.getTransitiveDeps(defDepsItem, variants, classMaps, totalDeps, force)
                localDeps.update(otherdeps)
                return localDeps

            # Process own deps
            console.debug("%s#%s dependencies:" % (classId, methodId))
            console.indent()

            if isinstance(attribNode, Node):

                if (attribNode.getChild("function", False)       # is it a function(){..} value?
                    and not dependencyItem.isCall                # and the reference was no call
                   ):
                    function_pruned = True
                    pass                                         # don't lift those deps
                else:
                    # Get the method's immediate deps
                    # TODO: is this the right API?!
                    depslist = []
                    self._analyzeClassDepsNode(attribNode, depslist, inLoadContext=False)
                    console.debug( "shallow dependencies: %r" % (depslist,))

                    # This depends on attribNode belonging to current class
                    my_ignores = self.getHints("ignoreDeps") + self.getHints("optionalDeps")
                    my_ignores = map(MetaIgnore, my_ignores)

                    for depsItem in depslist:
                        if depsItem in totalDeps:
                            continue
                        if depsItem.name in my_ignores:
                            continue
                        if self.resultAdd(depsItem, localDeps):
                            # Recurse dependencies
                            downstreamDeps = getTransitiveDepsR(depsItem, variants, totalDeps.union(localDeps))
                            localDeps.update(downstreamDeps)

            # Cache update
            # ---   i cannot cache currently, if the deps of a function are pruned
            #       when the function is passed as a ref, rather than called (s. above
            #       around 'attribNode.getChild("function",...)')
            if not function_pruned:
                cache.write(cacheId, localDeps, memory=True, writeToFile=False)
             
            console.outdent()
            return localDeps
Ejemplo n.º 34
0
    def depsItem_from_node(self, node):
        scope = node.scope
        # some initializations (might get refined later)
        depsItem = DependencyItem('', '', '')
        depsItem.name = ''
        depsItem.attribute = ''
        depsItem.requestor = self.id
        depsItem.line = node.get("line", -1)
        depsItem.isLoadDep = scope.is_load_time
        depsItem.needsRecursion = False
        depsItem.isCall = False
        depsItem.node = node
        is_lib_class = False
        var_root = treeutil.findVarRoot(
            node
        )  # various of the tests need the var (dot) root, rather than the head symbol (like 'qx')

        # .isCall
        if treeutil.isCallOperand(var_root):  # it's a function call or new op.
            depsItem.isCall = True  # interesting when following transitive deps

        # .name, .attribute
        assembled = (treeutil.assembleVariable(node))[0]
        className, classAttribute = self._splitQxClass(assembled)
        assembled_parts = assembled.split('.')
        if not className:
            if "." in assembled:
                className = '.'.join(assembled_parts[:-1])
                classAttribute = assembled_parts[-1]
                #className, classAttribute = assembled.split('.')[:2]
            else:
                className = assembled
        else:
            is_lib_class = True
        # we allow self-references, to be able to track method dependencies within the same class
        if assembled_parts[0] == 'this':
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        elif scope.is_defer and assembled_parts[0] in DEFER_ARGS:
            className = self.id
            is_lib_class = True
            if '.' in assembled:
                classAttribute = assembled_parts[1]
        if is_lib_class and not classAttribute:  # see if we have to provide 'construct'
            if treeutil.isNEWoperand(var_root):
                classAttribute = 'construct'
        depsItem.name = className
        depsItem.attribute = classAttribute

        # .needsRecursion
        # Mark items that need recursive analysis of their dependencies (bug#1455)
        #if self.followCallDeps(var_root, self.id, className, isLoadTime):
        #if self.id=='qx.bom.element.Style' and depsItem.attribute=='__detectVendorProperties':
        #    import pydb; pydb.debugger()
        if (is_lib_class and scope.is_load_time
                and (treeutil.isCallOperand(var_root)
                     or treeutil.isNEWoperand(var_root))):
            depsItem.needsRecursion = True

        return depsItem