Index: src/CodeTools/DeclStats.cc
===================================================================
--- src/CodeTools/DeclStats.cc	(revision 326cd2b2de09952dae86dcf87761062515a32068)
+++ src/CodeTools/DeclStats.cc	(revision 15d248e27c5fb45d6ac85cab858683e7c488940f)
@@ -23,4 +23,5 @@
 #include <utility>                 // for pair, make_pair
 
+#include "Common/PassVisitor.h"
 #include "Common/SemanticError.h"  // for SemanticError
 #include "Common/VectorMap.h"      // for VectorMap
@@ -35,5 +36,5 @@
 namespace CodeTools {
 
-	class DeclStats : public Visitor {
+	struct DeclStats : public WithShortCircuiting {
 		template<typename T>
 		static void sum(T& a, const T& b) { a += b; }
@@ -126,7 +127,7 @@
 			ArgPackStats assn_returns;
 
-			Stats() : n_decls(0), n_type_params(), n_generic_params(), n_generic_nesting(), 
-				by_name(), basic_type_names(), generic_type_names(), compound_type_names(), 
-				basic_type_decls(), generic_type_decls(), compound_type_decls(), params(), 
+			Stats() : n_decls(0), n_type_params(), n_generic_params(), n_generic_nesting(),
+				by_name(), basic_type_names(), generic_type_names(), compound_type_names(),
+				basic_type_decls(), generic_type_decls(), compound_type_decls(), params(),
 				returns(), n_assns(), assn_params(), assn_returns() {}
 
@@ -165,6 +166,6 @@
 		std::map<std::pair<unsigned, unsigned>, unsigned> exprs_by_fanout_at_depth;
 
-		void countType( const std::string& name, unsigned& n, std::unordered_map<std::string, 
-				unsigned>& names, std::unordered_map<std::string, unsigned>& decls, 
+		void countType( const std::string& name, unsigned& n, std::unordered_map<std::string,
+				unsigned>& names, std::unordered_map<std::string, unsigned>& decls,
 				std::unordered_set<std::string>& elSeen ) {
 			++n;
@@ -177,5 +178,5 @@
 		}
 
-		void analyzeSubtype( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen, 
+		void analyzeSubtype( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen,
 				unsigned& n_poly, bool& seen_poly, unsigned& max_depth, unsigned depth ) {
 			unsigned x;
@@ -183,6 +184,6 @@
 		}
 
-		void analyzeSubtypes( std::list<DeclarationWithType*>& tys, Stats& stats, 
-				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+		void analyzeSubtypes( std::list<DeclarationWithType*>& tys, Stats& stats,
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly,
 				unsigned& max_depth, unsigned depth, unsigned& n_subs ) {
 			for ( DeclarationWithType* dwt : tys ) {
@@ -193,6 +194,6 @@
 		}
 
-		void analyzeSubtypes( std::list<Expression*>& tys, Stats& stats, 
-				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+		void analyzeSubtypes( std::list<Expression*>& tys, Stats& stats,
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly,
 				unsigned& max_depth, unsigned depth ) {
 			for ( Expression* expr : tys ) {
@@ -204,6 +205,6 @@
 		}
 
-		void analyzeSubtypes( std::list<Type*>& tys, Stats& stats, 
-				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly, 
+		void analyzeSubtypes( std::list<Type*>& tys, Stats& stats,
+				std::unordered_set<std::string>& elSeen, unsigned& n_poly, bool& seen_poly,
 				unsigned& max_depth, unsigned depth ) {
 			for ( Type* ty : tys ) {
@@ -212,6 +213,6 @@
 		}
 
-		void analyzeType( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen, 
-				unsigned& n_basic, unsigned& n_generic, unsigned& n_poly, unsigned& n_agg,  
+		void analyzeType( Type* ty, Stats& stats, std::unordered_set<std::string>& elSeen,
+				unsigned& n_basic, unsigned& n_generic, unsigned& n_poly, unsigned& n_agg,
 				bool& seen_poly, unsigned& max_depth, unsigned depth = 0 ) {
 			if ( BasicType* bt = dynamic_cast<BasicType*>(ty) ) {
@@ -221,33 +222,33 @@
 			} else if ( PointerType* pt = dynamic_cast<PointerType*>(ty) ) {
 				std::string name = "*";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtype( 
+				analyzeSubtype(
 					pt->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( 1 );
 			} else if ( ArrayType* at = dynamic_cast<ArrayType*>(ty) ) {
 				std::string name = "[]";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtype( 
+				analyzeSubtype(
 					at->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( 1 );
 			} else if ( ReferenceType* rt = dynamic_cast<ReferenceType*>(ty) ) {
 				std::string name = "&";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtype( 
+				analyzeSubtype(
 					rt->get_base(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( 1 );
 			} else if ( FunctionType* ft = dynamic_cast<FunctionType*>(ty) ) {
 				std::string name = "(*)";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
 				unsigned n_subs = 0;
-				analyzeSubtypes( 
-					ft->get_returnVals(), stats, elSeen, n_poly, seen_poly, max_depth, depth, 
+				analyzeSubtypes(
+					ft->get_returnVals(), stats, elSeen, n_poly, seen_poly, max_depth, depth,
 					n_subs );
-				analyzeSubtypes( 
-					ft->get_parameters(), stats, elSeen, n_poly, seen_poly, max_depth, depth, 
+				analyzeSubtypes(
+					ft->get_parameters(), stats, elSeen, n_poly, seen_poly, max_depth, depth,
 					n_subs );
 				++stats.n_generic_params.at( n_subs );
@@ -257,6 +258,6 @@
 					seen_poly = true;
 				}
-				countType( 
-					vt->get_name(), n_agg, stats.compound_type_names, stats.compound_type_decls, 
+				countType(
+					vt->get_name(), n_agg, stats.compound_type_names, stats.compound_type_decls,
 					elSeen );
 				update_max( max_depth, depth );
@@ -264,11 +265,11 @@
 				std::list<Expression*>& params = st->get_parameters();
 				if ( params.empty() ) {
-					countType( 
-						st->get_name(), n_agg, stats.compound_type_names, 
+					countType(
+						st->get_name(), n_agg, stats.compound_type_names,
 						stats.compound_type_decls, elSeen );
 					update_max( max_depth, depth );
 				} else {
-					countType( 
-						st->get_name(), n_generic, stats.generic_type_names, 
+					countType(
+						st->get_name(), n_generic, stats.generic_type_names,
 						stats.generic_type_decls, elSeen);
 					analyzeSubtypes( params, stats, elSeen, n_poly, seen_poly, max_depth, depth );
@@ -277,12 +278,12 @@
 			} else if ( TupleType* tt = dynamic_cast<TupleType*>(ty) ) {
 				std::string name = "[,]";
-				countType( 
+				countType(
 					name, n_generic, stats.generic_type_names, stats.generic_type_decls, elSeen);
-				analyzeSubtypes( 
+				analyzeSubtypes(
 					tt->get_types(), stats, elSeen, n_poly, seen_poly, max_depth, depth );
 				++stats.n_generic_params.at( tt->size() );
 			} else if ( dynamic_cast<VarArgsType*>(ty) ) {
 				std::string name = "...";
-				countType( 
+				countType(
 					name, n_agg, stats.compound_type_names, stats.compound_type_decls, elSeen );
 				update_max( max_depth, depth );
@@ -299,6 +300,6 @@
 
 		/// Update arg pack stats based on a declaration list
-		void analyze( Stats& stats, std::unordered_set<std::string>& seen, 
-				std::unordered_set<std::string>& elSeen, ArgPackStats& pstats, 
+		void analyze( Stats& stats, std::unordered_set<std::string>& seen,
+				std::unordered_set<std::string>& elSeen, ArgPackStats& pstats,
 				std::list<DeclarationWithType*>& decls ) {
 			std::unordered_set<std::string> types;
@@ -309,5 +310,5 @@
 			unsigned n_agg = 0;             ///< number of non-generic aggregate types
 			unsigned n_new = 0;             ///< number of new types
-			
+
 			for ( auto decl : decls ) {
 				Type* dt = decl->get_type();
@@ -322,9 +323,9 @@
 				bool seen_poly = false;
 				unsigned max_depth = 0;
-				analyzeType( 
+				analyzeType(
 					dt, stats, elSeen, n_basic, n_generic, n_poly, n_agg, seen_poly, max_depth );
 				++stats.n_generic_nesting.at( max_depth );
 			}
-			
+
 			++pstats.n.at( n );
 			++pstats.n_basic.at( n_basic );
@@ -362,46 +363,37 @@
 
 	public:
-		using Visitor::visit;
-
-		virtual void visit( FunctionDecl *decl ) {
+		void previsit( 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 ) {
-				maybeAccept( decl->get_statements(), *this );
-				return;
-			}
-
-			Stats& stats = for_linkage[ ind_for_linkage[ decl->get_linkage() ] ];
-
-			++stats.n_decls;
-			FunctionType* fnTy = decl->get_functionType();
-			const Type::ForallList& forall = fnTy->get_forall();
-			++stats.n_type_params.at( forall.size() );
-			unsigned n_assns = 0;
-			for ( TypeDecl* fdecl : forall ) {
-				n_assns += fdecl->get_assertions().size();
-				for ( DeclarationWithType* assn : fdecl->get_assertions() ) {
-					FunctionType *assnTy = 0;
-					if ( ObjectDecl *assnObj = dynamic_cast<ObjectDecl*>(assn) ) {
-						if ( PointerType *ptrTy = dynamic_cast<PointerType*>(assnObj->get_type()) ) {
-							assnTy = dynamic_cast<FunctionType*>(ptrTy->get_base());
-						} else assnTy = dynamic_cast<FunctionType*>(assnObj->get_type());
-					} else if ( FunctionDecl *assnDecl = dynamic_cast<FunctionDecl*>(assn) ) {
-						assnTy = assnDecl->get_functionType();
+			const std::string& mangleName = decl->get_mangleName().empty() ? decl->name : decl->get_mangleName();
+			if ( seen_names.insert( mangleName ).second ) {
+				Stats& stats = for_linkage[ ind_for_linkage[ decl->linkage ] ];
+
+				++stats.n_decls;
+				FunctionType* fnTy = decl->type;
+				const Type::ForallList& forall = fnTy->forall;
+				++stats.n_type_params.at( forall.size() );
+				unsigned n_assns = 0;
+				for ( TypeDecl* fdecl : forall ) {
+					n_assns += fdecl->assertions.size();
+					for ( DeclarationWithType* assn : fdecl->assertions ) {
+						FunctionType *assnTy = nullptr;
+						if ( ObjectDecl *assnObj = dynamic_cast<ObjectDecl*>(assn) ) {
+							if ( PointerType *ptrTy = dynamic_cast<PointerType*>(assnObj->get_type()) ) {
+								assnTy = dynamic_cast<FunctionType*>(ptrTy->base);
+							} else assnTy = dynamic_cast<FunctionType*>(assnObj->get_type());
+						} else if ( FunctionDecl *assnDecl = dynamic_cast<FunctionDecl*>(assn) ) {
+							assnTy = assnDecl->type;
+						}
+						if ( assnTy ) analyzeFunc( assnTy, stats, stats.assn_params, stats.assn_returns );
 					}
-					if ( assnTy ) analyzeFunc( assnTy, stats, stats.assn_params, stats.assn_returns );
-				}
-			}
-			++stats.n_assns[ n_assns ];
-
-			++stats.by_name[ decl->get_name() ];
-
-			analyzeFunc( fnTy, stats, stats.params, stats.returns );
-
-			// analyze expressions in decl statements
-			maybeAccept( decl->get_statements(), *this );
-		}
-
-		virtual void visit( UntypedExpr *expr ) {
+				}
+				++stats.n_assns[ n_assns ];
+				++stats.by_name[ decl->name ];
+				analyzeFunc( fnTy, stats, stats.params, stats.returns );
+			}
+		}
+
+		void previsit( UntypedExpr *expr ) {
+			visit_children = false;
 			analyzeExpr( expr, 0 );
 		}
@@ -536,11 +528,11 @@
 	};
 
-	const unsigned DeclStats::ind_for_linkage[] 
+	const unsigned DeclStats::ind_for_linkage[]
 		= { 7, 7, 2, 1,   7, 7, 7, 3,   4, 7, 6, 5,   7, 7, 7, 0 };
 
 	void printDeclStats( std::list< Declaration * > &translationUnit ) {
-		DeclStats stats;
+		PassVisitor<DeclStats> stats;
 		acceptAll( translationUnit, stats );
-		stats.print();
+		stats.pass.print();
 	}
 
