Exemplo n.º 1
0
 def __init__(self, node, c=None):
     if node == None or node.name != "FieldDeclaration":
         self.mods = []
         self.name = ""
         self.type = None
     else:
         self.mods = ast.get_modifiers(node.find_child("Modifiers"))
         self.name = node.find_child("Identifier").value.value
         self.type = c.get_type(node.find_child("Type"))
         node.obj  = self
     if c != None and c.interface:
         self.mods.append("Abstract")
     self.node = node
     self.declared_in = c
Exemplo n.º 2
0
 def __init__(self, node, c=None):
     if node == None or (node.name != "MethodDeclaration" and node.name != "ConstructorDeclaration"):
         self.mods = []
         self.type = None
         self.name = ""
         self.params = []
     else:
         self.mods = ast.get_modifiers(node.find_child("Modifiers"))
         if node.name == "ConstructorDeclaration":
             self.type = None
         else:
             self.type = c.get_type(node.find_child("Type"))
         self.name = node.find_child("Identifier").value.value
         self.params = c.get_parameters(node.find_child("Parameters"))
         node.obj = self
     if c != None and c.interface:
         self.mods.append("Abstract")
     self.node = node
     self.declared_in = c
Exemplo n.º 3
0
def class_hierarchy(ast_list, pkg_index, type_index):
    class_dict = {}

    # scan ASTs for classes
    for a in ast_list:
        if len(a.children) == 0:
            continue

        # figure out fully qualified name
        package = a[0][0]
        pkg_name = ast.get_qualified_name(package)
        if pkg_name == "":
            pkg_name = "MAIN_PKG"
        decl = a[0][3]
        name = decl[1][0].value.value


        # create class
        c = Class(pkg_name, name)
        #print("@#", c.name)
        c.interface = decl.name != "ClassDeclaration"
        c.mods = ast.get_modifiers(decl.find_child("Modifiers"))
        
        c.extends = decl.find_child("Superclass")
        c.implements = decl.find_child("Interfaces")

        c.node = decl
        decl.obj = c
        c.env = type_index[c.name]
        c.type_index = type_index

        tn = None
        if c.extends != None:
            tn = c.extends.find_child("Type")
        
        if tn != None:
            c.extends = typelink.resolve_type(c.type_index, c.env, c.pkg, tn)
        else:
            if c.interface == False and c.name != "java.lang.Object":
                c.extends = "java.lang.Object"
            else:
                c.extends = ""

        c.implements = [typelink.resolve_type(c.type_index, c.env, c.pkg, tn)
            for tn in c.implements.children]

        # An interface must not be repeated in an implements clause, or in an extends clause of an interface. (JLS 8.1.4, dOvs simple constraint 3) 
        for i in c.implements:
            if len([x for x in c.implements if x == i]) > 1:
                logging.error("%s is an interface that is repeated (for %s)."
                    % (i, c.name))
                sys.exit(42)
        
        #decl.pprint()
        """
        print(c)
        print(c.interface)
        print("Extends:    ", c.extends)
        print("Implements: ", c.implements)
        """

        if name in class_dict:
            logging.error("SHOULD NOT HAPPEN: %s has already been declared." % name)
            sys.exit(42)

        class_dict[c.name] = c

    # create hiearchy
    for c in class_dict.values():
        if c.extends != "":
            if c.extends not in class_dict:
                logging.error("%s superclass does not exist (for %s)."
                    % (c.extends, c.name))
                sys.exit(42)
            else:
                c.extends = class_dict[c.extends]
                # A class must not extend an interface. (JLS 8.1.3, dOvs simple constraint 1) 
                if c.extends.interface:
                    logging.error("%s is an interface (for %s)."
                        % (c.extends, c.name))
                    sys.exit(42)
                # A class must not extend a final class. (JLS 8.1.1.2, 8.1.3, dOvs simple constraint 4)
                if "Final" in c.extends.mods:
                    logging.error("%s is final and is extended (for %s)."
                        % (c.extends, c.name))
                    sys.exit(42)
                    
        else:
            c.extends = None

        for i in c.implements:
            if i not in class_dict:
                logging.error("%s interface does not exist (for %s)."
                    % (i, c.name))
                sys.exit(42)
        c.implements = [class_dict[x] for x in c.implements]
        for i in c.implements:
            # A class must not implement a class. (JLS 8.1.4, dOvs simple constraint 2) 
            # An interface must not extend a class. (JLS 9.1.2) 
            if i.interface != True:
                logging.error("%s is not an interface (for %s)."
                    % (i, c.name))
                sys.exit(42)

    # check for cycles
    # The hierarchy must be acyclic. (JLS 8.1.3, 9.1.2, dOvs well-formedness constraint 1) 
    for c in class_dict.values():
        cycle_detection(c, [])

    # create fields and methods and fill in declares
    for c in class_dict.values():
        # Fields
        fields = c.node.find_child("Fields")
        if fields != None: # Interfaces have no fields
            for f in fields:
                ff = Field(f, c)
                if ff in c.declare:
                    logging.error("Duplicate declaration of field %s" % ff)
                    sys.exit(42)
                c.declare.append(ff)

        # Methods
        methods = c.node.find_child("Methods")
        for m in methods:
            mm = Method(m, c)
            # A class or interface must not declare two methods with the same signature (name and parameter types). (JLS 8.4, 9.4, dOvs well-formedness constraint 2) 
            # A class or interface must not contain (declare or inherit) two methods with the same signature but different return types (JLS 8.1.1.1, 8.4, 8.4.2, 8.4.6.3, 8.4.6.4, 9.2, 9.4.1, dOvs well-formedness constraint 3) 
            if mm in c.declare:
                logging.error("Duplicate declaration of method %s" % mm)
                sys.exit(42)
            c.declare.append(mm)

        # Constructors
        constructors = c.node.find_child("Constructors")
        if constructors == None:
            constructors = []
        for con in constructors:
            ccon = Method(con, c)
            # A class must not declare two constructors with the same parameter types (dOvs 8.8.2, simple constraint 5) 
            if ccon in c.declare:
                logging.error("Duplicate declaration of constructor %s" % ccon)
                sys.exit(42)
            c.declare.append(ccon)

        # annoying edge case check yo
        if c.interface:
            m = Method(None, c)
            m.type = "java.lang.Class"
            m.name = "getClass"
            m.params = []
            if m in c.declare:
                logging.error("interface declared a final method:", m)
                sys.exit(42)

        # Implicit declare for interface without superinterface
        if c.interface and len(c.implements) == 0:
            # Add publics of java.lang.Object
            for (n, t) in [
                    ("equals", "Boolean"),
                    ("toString", "java.lang.String"),
                    ("hashCode", "Int"),
                    ("getClass", "java.lang.Class")
                    ]:
                m = Method(None, c)
                m.mods = ["Public", "Abstract"]
                m.type = t
                m.name = n
                m.params = []
                m.node = node.ASTNode('MethodDeclaration')
                m.node.obj = m
                if (n == "equals"):
                    m.params.append("java.lang.Object")
                elif (n == "getClass"):
                    pass
                if m not in c.declare:
                    c.declare.append(m)
                elif m.type not in [x.type for x in c.declare if x == m]:
                    logging.error("Implicit decl of %s return type does not match" % m)
                    sys.exit(42)

    # fill in inherits
    # Apologies for this code, but I'm just going to loop through the dictionary
    # until I have filled out all inherit data, since I don't want to create
    # a top-down tree structure for the class hierarchy
    continue_inherits = True
    while continue_inherits:
        continue_inherits = False
        for c in class_dict.values():
            if (c.extends != None and c.extends.inherit == None) or None in [x.inherit for x in c.implements]:
                continue_inherits = True
                continue
            elif c.inherit != None:
                continue
            else:
                c.inherit = determine_inherit(c)

    # final checks
    for c in class_dict.values():
        # A class that contains (declares or inherits) any abstract methods must be abstract. (JLS 8.1.1.1, well-formedness constraint 4)
        if c.interface != True and "Abstract" not in c.mods and True in [True for x in contain(c) if "Abstract" in x.mods]:
            logging.error("%s is not abstract but contains an abstract method" % c)
            sys.exit(42)

        # Implicit default constructor check
        if c.extends != None:
            cons_name = c.extends.name.split('.')[-1]
            if Temp_Constructor(cons_name, []) not in contain(c.extends):
                logging.error("%s has a superclass without a default constructor" % c.name)
                sys.exit(42)

    return class_dict