Associates various constructs with each other.

def correlate(self):
        """
        Associates various constructs with each other.
        """

        print("Correlating information from different parts of your project...")
                        
        non_local_mods = INTRINSIC_MODS        
        for item in self.settings['extra_mods']:
            i = item.index(':')
            if i < 0:
                print('Warning: could not parse extra modules ""'.format(item))
                continue
            name = item[:i].strip()
            url = item[i+1:].strip()
            non_local_mods[name.lower()] = '<a href="{}">{}</a>'.format(url,name)
        
        # Match USE statements up with the right modules
        for s in self.modules:
            id_mods(s, self.modules, non_local_mods, self.submodules)
        for s in self.procedures:
            id_mods(s, self.modules, non_local_mods, self.submodules)
        for s in self.programs:
            id_mods(s, self.modules, non_local_mods, self.submodules)
        for s in self.submodules:
            id_mods(s, self.modules, non_local_mods, self.submodules)
        for s in self.blockdata:
            id_mods(s, self.modules, non_local_mods, self.submodules)
            
        # Get the order to process other correlations with
        deplist = {}
        
        def get_deps(item):
            uselist = [m[0] for m in item.uses]
            for proc in getattr(item,'subroutines',[]):
                uselist.extend(get_deps(proc))
            for proc in getattr(item,'functions',[]):
                uselist.extend(get_deps(proc))
            for proc in getattr(item,'modprocedures',[]):
                uselist.extend(get_deps(proc))
            return uselist
        
        for mod in self.modules:
            uselist = get_deps(mod)
            uselist = [m for m in uselist if type(m) == ford.sourceform.FortranModule]
            deplist[mod] = set(uselist)
            mod.deplist = uselist
        for mod in self.submodules:
            if type(mod.ancestor_mod) is ford.sourceform.FortranModule:
                uselist = get_deps(mod)
                uselist = [m for m in uselist if type(m) == ford.sourceform.FortranModule]
                if mod.ancestor:
                    if type(mod.ancestor) is ford.sourceform.FortranSubmodule:
                        uselist.insert(0,mod.ancestor)
                    elif self.settings['warn'].lower() == 'true':
                        print('Warning: could not identify parent SUBMODULE of SUBMODULE ' + mod.name)
                else:
                    uselist.insert(0,mod.ancestor_mod)
                mod.deplist = uselist
                deplist[mod] = set(uselist)
            elif self.settings['warn'].lower() == 'true':
                print('Warning: could not identify parent MODULE of SUBMODULE ' + mod.name)
        # Get dependencies for programs and top-level procedures as well,
        # if dependency graphs are to be produced
        if self.settings['graph'].lower() == 'true':
            for proc in self.procedures:
                proc.deplist = set([m for m in get_deps(proc) if type(m) == ford.sourceform.FortranModule])
            for prog in self.programs:
                prog.deplist = set([m for m in get_deps(prog) if type(m) == ford.sourceform.FortranModule])
            for block in self.blockdata:
                block.deplist = set([m for m in get_deps(block) if type(m) == ford.sourceform.FortranModule])
        ranklist = toposort.toposort_flatten(deplist)
        for proc in self.procedures:
            if proc.parobj == 'sourcefile': ranklist.append(proc)
        ranklist.extend(self.programs)
        ranklist.extend(self.blockdata)

        # Perform remaining correlations for the project
        for container in ranklist:
            if type(container) != str: container.correlate(self)
        for container in ranklist:
            if type(container) != str: container.prune()

        if self.settings['project_url'] == '.':
            url = '..'
        else:
            url = self.settings['project_url']

        for sfile in self.files:
            for module in sfile.modules:
                for function in module.functions:
                    self.procedures.append(function)
                for subroutine in module.subroutines:
                    self.procedures.append(subroutine)
                for interface in module.interfaces:
                    self.procedures.append(interface)
                for absint in module.absinterfaces:
                    self.absinterfaces.append(absint)
                for dtype in module.types:
                    self.types.append(dtype)

            for module in sfile.submodules:
                for function in module.functions:
                    self.procedures.append(function)
                for subroutine in module.subroutines:
                    self.procedures.append(subroutine)
                for function in module.modfunctions:
                    self.submodprocedures.append(function)
                for subroutine in module.modsubroutines:
                    self.submodprocedures.append(subroutine)
                for modproc in module.modprocedures:
                    self.submodprocedures.append(modproc)
                for interface in module.interfaces:
                    self.procedures.append(interface)
                for absint in module.absinterfaces:
                    self.absinterfaces.append(absint)
                for dtype in module.types:
                    self.types.append(dtype)

            for program in sfile.programs:
                for function in program.functions:
                    self.procedures.append(function)
                for subroutine in program.subroutines:
                    self.procedures.append(subroutine)
                for interface in program.interfaces:
                    self.procedures.append(interface)
                for absint in program.absinterfaces:
                    self.absinterfaces.append(absint)
                for dtype in program.types:
                    self.types.append(dtype)

            for block in sfile.blockdata:
                for dtype in block.types:
                    self.types.append(dtype)

        def sum_lines(*argv, **kwargs):
            """ Wrapper for minimizing memory consumption """
            routine = kwargs.get('func', 'num_lines')
            n = 0
            for arg in argv:
                for item in arg:
                    n += getattr(item, routine)
            return n
        self.mod_lines = sum_lines(self.modules, self.submodules)
        self.proc_lines = sum_lines(self.procedures)
        self.file_lines = sum_lines(self.files)
        self.type_lines = sum_lines(self.types)
        self.type_lines_all = sum_lines(self.types, func='num_lines_all')
        self.absint_lines = sum_lines(self.absinterfaces)
        self.prog_lines = sum_lines(self.programs)
        self.block_lines = sum_lines(self.blockdata)
        print()