class SubroutineAggregator {

    public List<Subroutine> aggregate(final Map<String, SubroutineDeclaration> declarations,
            final List<SubroutineDefinition> definitions,
            final Map<String, SubroutineDocumentation> subroutineDocumentation) {
        if (declarations == null) {
            throw new IllegalArgumentException("Declarations cannot be null.");
        }

        if (definitions == null) {
            throw new IllegalArgumentException("Definitions cannot be null.");
        }

        if (subroutineDocumentation == null) {
            throw new IllegalArgumentException("Subroutine documentation cannot be null.");
        }

        final EtmPoint point = PointFactory.getPoint(getClass(), "aggregate(Map, List, Map)");
        try {
            final List<Subroutine> subroutines = new ArrayList<Subroutine>(definitions.size());
            for (final SubroutineDefinition definition : definitions) {
                final String subroutineName = definition.getName();
                final SubroutineDocumentation documentation = subroutineDocumentation.get(subroutineName);
                final List<String> argumentNames = definition.getArgumentNames();
                final List<SubroutineArgument> arguments = new ArrayList<SubroutineArgument>(argumentNames.size());
                // If typing information can be determined...
                if (declarations.containsKey(subroutineName)) {
                    final SubroutineDeclaration declaration = declarations.get(subroutineName);
                    final List<SubroutineArgumentDeclaration> argumentDeclarations = declaration.getArguments();
                    for (int argumentPosition = 0; argumentPosition < argumentNames.size()
                            && argumentPosition < argumentDeclarations.size(); argumentPosition++) {
                        arguments.add(newArgument(argumentDeclarations.get(argumentPosition), documentation));
                    }
                    subroutines
                            .add(newSubroutine(subroutineName, arguments, declaration.getReturnType(), documentation));
                } else {
                    for (final String argumentName : argumentNames) {
                        arguments.add(newArgument(argumentName, documentation));
                    }
                    subroutines.add(
                            newSubroutine(subroutineName, arguments, Subroutine.UNKNOWN_RETURN_TYPE, documentation));
                }
            }
            return subroutines;
        } finally {
            point.collect();
        }
    }

}