Index: src/CodeTools/DeclStats.cc
===================================================================
--- src/CodeTools/DeclStats.cc	(revision 41a7137de5c42b8cb1bc898ffbadea8141f9c410)
+++ src/CodeTools/DeclStats.cc	(revision fa2de9578cda12bc9dfa0f3bc8f2c87a3754e630)
@@ -17,9 +17,152 @@
 
 #include <iostream>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+
+#include "Common/VectorMap.h"
+#include "Parser/LinkageSpec.h"
+#include "SynTree/Declaration.h"
+#include "SynTree/Visitor.h"
 
 namespace CodeTools {
+	
+	class DeclStats : public Visitor {
+		struct Stats {
+			unsigned n_decls;     ///< Total number of declarations
+			unsigned mono_decls;  ///< Monomorphic declarations
+			unsigned poly_decls;  ///< Polymorphic declarations
+			/// Count of declarations with each name
+			std::unordered_map<std::string, unsigned> by_name;
+			/// Count of declarations with each number of parameters
+			VectorMap<unsigned> by_params;
+			/// Count of declarations with each number of return types
+			VectorMap<unsigned> by_returns;
+
+			Stats() : n_decls(0), mono_decls(0), poly_decls(0), by_name() {}
+
+			Stats& operator+= (const Stats& o) {
+				n_decls += o.n_decls;
+				mono_decls += o.mono_decls;
+				poly_decls += o.poly_decls;
+				
+				for ( auto& entry : o.by_name ) {
+					by_name[ entry.first ] += entry.second;
+				}
+				
+				by_params.reserve( o.by_params.size() );
+				for ( unsigned i = 0; i < o.by_params.size(); ++i ) {
+					by_params[i] += o.by_params[i];
+				}
+
+				by_returns.reserve( o.by_returns.size() );
+				for ( unsigned i = 0; i < o.by_returns.size(); ++i ) {
+					by_returns[i] += o.by_returns[i];
+				}
+
+				return *this;
+			}
+		};
+
+		Stats for_linkage[LinkageSpec::NoOfSpecs];   ///< Stores separate stats per linkage
+		std::unordered_set<std::string> seen_names;  ///< Stores manglenames already seen to avoid double-counting
+		Stats total;
+
+	public:
+		using Visitor::visit;
+
+		virtual void visit( FunctionDecl *decl ) {
+			// skip if already seen declaration for this function
+			const std::string& mangleName = decl->get_mangleName().empty() ? decl->get_name() : decl->get_mangleName();
+			if ( ! seen_names.insert( mangleName ).second ) return;
+			
+			Stats& stats = for_linkage[ decl->get_linkage() ];
+
+			++stats.n_decls;
+			FunctionType* fnTy = decl->get_functionType();
+			if ( fnTy->get_forall().empty() ) ++stats.mono_decls; else ++stats.poly_decls;
+
+			++stats.by_name[ decl->get_name() ];
+
+			unsigned n_params = 0;
+			for ( auto pdecl : fnTy->get_parameters() ) { n_params += pdecl->get_type()->size(); }
+			++stats.by_params.at( n_params );
+
+			unsigned n_returns = 0;
+			for ( auto rdecl : fnTy->get_returnVals() ) { n_returns += rdecl->get_type()->size(); }
+			++stats.by_returns.at( n_returns );
+		}
+
+	private:
+		template<typename F>
+		void printAll( const char* name, F extract ) {
+			std::cout << "\"" << name << "\",";
+			for ( const auto& stats : for_linkage ) {
+				std::cout << "," << extract(stats);
+			}
+			std::cout << "," << extract(total) << std::endl;
+		}
+
+		template<typename F>
+		void printAllMap( const char* name, F extract ) {
+			for ( const auto& entry : extract(total) ) {
+				const auto& key = entry.first;
+				std::cout << "\"" << name << "\"," << key;
+				for ( const auto& stats : for_linkage ) {
+					const auto& map = extract(stats);
+					auto it = map.find( key );
+					if ( it == map.end() ) std::cout << ",0";
+					else std::cout << "," << it->second;
+				}
+				std::cout  << "," << entry.second << std::endl;
+			}
+		}
+
+		template<typename F>
+		void printAllHisto( const char* name, F extract ) {
+			VectorMap<unsigned> histos[LinkageSpec::NoOfSpecs];
+			VectorMap<unsigned> thisto;
+
+			for ( const auto& entry : extract(total) ) { ++thisto.at( entry.second ); }
+
+			for ( unsigned i = 0; i < LinkageSpec::NoOfSpecs; ++i ) {
+				// can't be a higher count in one of the sub-histograms than the total
+				histos[i].reserve( thisto.size() );
+
+				for ( const auto& entry : extract(for_linkage[i]) ) { ++histos[i][entry.second]; }
+			}
+
+			for ( unsigned i = 0; i < thisto.size(); ++i ) {
+				std::cout << "\"" << name << "\"," << i;
+				for ( const auto& histo : histos ) {
+					std::cout << "," << histo[i];
+				}
+				std::cout << "," << thisto[i] << std::endl;
+			}
+		}
+		
+	public:
+		void print() {
+			for ( auto& stats : for_linkage ) {
+				total += stats;
+			}
+
+			std::cout << ",,\"intrinsic\",\"Cforall\",\"C\",\"autogen\",\"builtin\",\"TOTAL\"" << std::endl;
+
+			printAll("mono_decls", [](const Stats& stats) { return stats.mono_decls; });
+			printAll("poly_decls", [](const Stats& stats) { return stats.poly_decls; });
+			printAll("n_decls", [](const Stats& stats) { return stats.n_decls; });
+			printAll("unique_names", [](const Stats& stats) { return stats.by_name.size(); });
+
+			printAllHisto("overloads", [](const Stats& stats) { return stats.by_name; });
+			printAllMap("n_params", [](const Stats& stats) { return stats.by_params; });
+			printAllMap("n_returns", [](const Stats& stats) { return stats.by_returns; });
+		}
+	};
 
 	void printDeclStats( std::list< Declaration * > &translationUnit ) {
-		std::cout << "DeclStats not yet implemented." << std::endl;
+		DeclStats stats;
+		acceptAll( translationUnit, stats );
+		stats.print();
 	}
 	
Index: src/CodeTools/DeclStats.h
===================================================================
--- src/CodeTools/DeclStats.h	(revision 41a7137de5c42b8cb1bc898ffbadea8141f9c410)
+++ src/CodeTools/DeclStats.h	(revision fa2de9578cda12bc9dfa0f3bc8f2c87a3754e630)
@@ -21,4 +21,5 @@
 namespace CodeTools {
 
+	/// Prints summary information about a translation unit's function declarations and calls
 	void printDeclStats( std::list< Declaration * > &translationUnit );
 	
