def patch(tree, classObj, featureMap): feature_names = featureMap[classObj.id] # get class map qxDefine = treeutil.findQxDefine(tree) classMap = treeutil.getClassMap(qxDefine) # go through features in 'members' and 'statics' for section in ("statics", "members"): if section in classMap: for feature, node in classMap[section].items(): # skip registered and used keys if feature in feature_names and feature_names[feature].hasref(): continue else: parent = node.parent assert parent.type == "keyvalue" #print "pruning: %s#%s" % (classObj.id, feature) parent.parent.removeChild(parent) # remove the entire feature from the map # remove from featureMap if feature in feature_names: del featureMap[classObj.id][feature] # decrease the ref counts of the contained dependees deps = [] classObj._analyzeClassDepsNode(node, deps, inLoadContext=False) # TODO: this is expensive (re-calculating deps)! # and it doesn't honor #ignores, so might decrease ref count of ignored # items! (which could lead to inconsistencies) # also, i'm calling a protected method outside the class hierarchy. for depItem in deps: if depItem.name in featureMap and depItem.attribute in featureMap[depItem.name]: depFeature = featureMap[depItem.name][depItem.attribute] depFeature.decref() # decrease reference count
def patch(tree, classObj, featureMap): # change this to 'False' if you want logging instead of function removal prune_dont_log = True feature_names = featureMap[classObj.id] # get class map qxDefine = treeutil.findQxDefine(tree) classMap = treeutil.getClassMap(qxDefine) # go through features in 'members' and 'statics' for section in ("statics", "members"): if section in classMap: for feature, node in classMap[section].items(): # skip registered and used keys if feature in feature_names and feature_names[feature].hasref(): continue else: parent = node.parent assert parent.type == "keyvalue" #print "static optimizing: %s#%s" % (classObj.id, feature) if prune_dont_log: # remove sub tree parent.parent.removeChild(parent) # remove the entire feature from the map # remove from featureMap if feature in feature_names: del featureMap[classObj.id][feature] # decrease the ref counts of the contained dependees decrementFromCode(classObj, node, featureMap) else: # OR: only add runtime logging to functions block = treeutil.selectNode(node, 'function/body/block/statements') if block: LogStmt = treegenerator.parse("console.warn('Static optimization would have removed: " + classObj.id + '#' + feature + "');") block.addChild(LogStmt, 0)
def class_declared_privates(self, class_def_node): try: class_map = treeutil.getClassMap(class_def_node) except tree.NodeAccessException: return for category in ('statics', 'members'): # collect all privates if category in class_map: private_keys = set() for key in class_map[category]: if self.reg_privs.match(key): private_keys.add(key) # go through uses of 'this' and 'that' that reference a private items = class_map[category].items() if category == "members" and 'construct' in class_map: # add checking constructor items.insert(0, ('construct', class_map['construct'].parent # to recover (value ...) )) for key,val in items: if val.children[0].type == 'function': function_privs = self.function_uses_local_privs(val.children[0]) for priv, node in function_privs: if priv not in private_keys: issue = warn("Using an undeclared private class feature: '%s'" % priv, self.file_name, node) self.issues.append(issue)
def patch(tree, id, feature_names): # get class map qxDefine = treeutil.findQxDefine(tree) classMap = treeutil.getClassMap(qxDefine) # go through features in 'members' and 'statics' for section in ("statics", "members"): if section in classMap: for key, node in classMap[section].items(): # skip registered keys if key in feature_names: continue # skip non-function attribs meth = None if node.type == 'function': meth = node else: meth = treeutil.selectNode(node, "function") if not meth: continue # prune else: parent = node.parent assert parent.type == "keyvalue" #print "pruning: %s#%s" % (id, key) parent.parent.removeChild(parent) # remove the entire key from the map
def patch(tree, classObj, featureMap): feature_names = featureMap[classObj.id] # get class map qxDefine = treeutil.findQxDefine(tree) classMap = treeutil.getClassMap(qxDefine) # go through features in 'members' and 'statics' for section in ("statics", "members"): if section in classMap: for feature, node in classMap[section].items(): # skip registered and used keys if feature in feature_names and feature_names[feature].hasref( ): continue else: parent = node.parent assert parent.type == "keyvalue" #print "pruning: %s#%s" % (classObj.id, feature) parent.parent.removeChild( parent) # remove the entire feature from the map # remove from featureMap if feature in feature_names: del featureMap[classObj.id][feature] # decrease the ref counts of the contained dependees decrementFromCode(classObj, node, featureMap)
def optimize(classDefine, classDefNodes): patchCount = 0 # get class map try: classMap = treeutil.getClassMap(classDefine) except tree.NodeAccessException: # this might happen when the second param is not a map literal return 0 if not "extend" in classMap: return 0 if classMap["extend"].type == "variable": superClass = treeutil.assembleVariable(classMap["extend"])[0] else: return 0 # interfaces can have a list-valued "extend", but we currently don't optimize those if "construct" in classMap: patchCount = optimizeConstruct(classMap["construct"], superClass, "construct", classDefNodes) if not "members" in classMap: return patchCount members = classMap["members"] for methodName, methodNode in members.items(): patchCount += optimizeConstruct(methodNode, superClass, methodName, classDefNodes) return patchCount
def class_declared_privates(self, class_def_node): try: class_map = treeutil.getClassMap(class_def_node) except tree.NodeAccessException: return for category in ('statics', 'members'): # collect all privates if category in class_map: private_keys = set() for key in class_map[category]: if self.reg_privs.match(key): private_keys.add(key) # go through uses of 'this' and 'that' that reference a private items = class_map[category].items() if category == "members" and 'construct' in class_map: # add checking constructor items.insert( 0, ( 'construct', class_map['construct']. parent # to recover (value ...) )) for key, val in items: if val.children[0].type == 'function': function_privs = self.function_uses_local_privs( val.children[0]) for priv, node in function_privs: if priv not in private_keys: warn( "Using an undeclared private class feature: '%s'" % priv, self.file_name, node)
def patch(tree, id, feature_names): # get class map qxDefine = treeutil.findQxDefine(tree) classMap = treeutil.getClassMap(qxDefine) # go through features in 'members' and 'statics' for section in ("statics", "members"): if section in classMap: for key, node in classMap[section].items(): # skip registered keys if key in feature_names: continue # skip non-function attribs meth = None if node.type == 'function': meth = node else: meth = treeutil.selectNode(node, "function") if not meth: continue # prune else: parent = node.parent assert parent.type == "keyvalue" #print "pruning: %s#%s" % (id, key) parent.parent.removeChild( parent) # remove the entire key from the map
def getClassMap(self, variants): tree = self.optimize( None, ["variants"], variants ) # TODO: this might incur an extra cached tree, if not(variants) qxDefine = treeutil.findQxDefine(tree) classMap = treeutil.getClassMap(qxDefine) return classMap
def node_is_defer_value(self, node): is_defer = False # find qxDefine in tree for qx_def_node in treeutil.findQxDefineR(self.root_node): class_map = treeutil.getClassMap(qx_def_node) if 'defer' in class_map and class_map['defer'] == node: is_defer = True break return is_defer
def _getType(self): if hasattr(self, "_type"): return self._type ast = self.tree() qxDefine = treeutil.findQxDefine(ast) classMap = treeutil.getClassMap(qxDefine) if 'type' in classMap: self._type = classMap['type'].get('value') elif 'extend' not in classMap: self._type = "static" # this is qx.Class.define semantics! else: self._type = "normal" return self._type
def findClassForMethod(clazzId, methodId, variants): def classHasOwnMethod(classAttribs, methId): candidates = {} candidates.update(classAttribs.get("members",{})) candidates.update(classAttribs.get("statics",{})) if "construct" in classAttribs: candidates.update(dict((("construct", classAttribs.get("construct")),))) if methId in candidates.keys(): return candidates[methId] # return the definition of the attribute else: return None # get the method name if methodId == u'': # corner case: the class is being called methodId = "construct" elif methodId == "getInstance": # corner case: singletons get this from qx.Class clazzId = "qx.Class" # TODO: getter/setter are also not statically available! # handle .call() ?! if clazzId in lang.BUILTIN: # these are automatically fullfilled, signal this return True, True elif clazzId not in self._classesObj: # can't further process non-qooxdoo classes return None, None tree = self._classesObj[clazzId].tree( variants) clazz = treeutil.findQxDefine(tree) classAttribs = treeutil.getClassMap(clazz) keyval = classHasOwnMethod(classAttribs, methodId) if keyval: return clazzId, keyval # inspect inheritance/mixins parents = [] extendVal = classAttribs.get('extend', None) if extendVal: extendVal = treeutil.variableOrArrayNodeToArray(extendVal) parents.extend(extendVal) includeVal = classAttribs.get('include', None) if includeVal: includeVal = treeutil.variableOrArrayNodeToArray(includeVal) parents.extend(includeVal) # go through all ancestors for parClass in parents: rclass, keyval = findClassForMethod(parClass, methodId, variants) if rclass: return rclass, keyval return None, None
def class_reference_fields(self, class_def_node): try: class_map = treeutil.getClassMap(class_def_node) except tree.NodeAccessException: return # only check members members_map = class_map['members'] if 'members' in class_map else {} for key, val in members_map.items(): value_node = val.children[0] if (value_node.type in ("map", "array") or (value_node.type == "operation" and value_node.get("operator")=="NEW")): ok = False at_hints = get_at_hints(value_node) if at_hints: ok = self.is_name_lint_filtered(key, at_hints, "ignoreReferenceField") if not ok: warn("Reference values are shared across all instances: '%s'" % key, self.file_name, value_node)
def patch(tree, classObj, featureMap): feature_names = featureMap[classObj.id] # get class map qxDefine = treeutil.findQxDefine(tree) classMap = treeutil.getClassMap(qxDefine) # go through features in 'members' and 'statics' for section in ("statics", "members"): if section in classMap: for feature, node in classMap[section].items(): # skip registered and used keys if feature in feature_names and feature_names[feature].hasref(): continue else: parent = node.parent assert parent.type == "keyvalue" #print "pruning: %s#%s" % (classObj.id, feature) parent.parent.removeChild(parent) # remove the entire feature from the map # remove from featureMap if feature in feature_names: del featureMap[classObj.id][feature] # decrease the ref counts of the contained dependees decrementFromCode(classObj, node, featureMap)
def getClassMap(self, variants): tree = self.tree () qxDefine = treeutil.findQxDefine (tree) classMap = treeutil.getClassMap (qxDefine) return classMap