Avoids unnecessary printing of call into to internal buffers;
Made the universal value printer safer when printing char[];
Removed duplicated code in InvokeWith;
Improved gmock_doctor.py.
diff --git a/include/gmock/gmock-printers.h b/include/gmock/gmock-printers.h
index 9900243..e233ef3 100644
--- a/include/gmock/gmock-printers.h
+++ b/include/gmock/gmock-printers.h
@@ -580,6 +580,41 @@
 #endif  // _MSC_VER
 };
 
+// UniversalPrintArray(begin, len, os) prints an array of 'len'
+// elements, starting at address 'begin'.
+template <typename T>
+void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) {
+  if (len == 0) {
+    *os << "{}";
+  } else {
+    *os << "{ ";
+    const size_t kThreshold = 18;
+    const size_t kChunkSize = 8;
+    // If the array has more than kThreshold elements, we'll have to
+    // omit some details by printing only the first and the last
+    // kChunkSize elements.
+    // TODO(wan@google.com): let the user control the threshold using a flag.
+    if (len <= kThreshold) {
+      PrintRawArrayTo(begin, len, os);
+    } else {
+      PrintRawArrayTo(begin, kChunkSize, os);
+      *os << ", ..., ";
+      PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os);
+    }
+    *os << " }";
+  }
+}
+// This overload prints a (const) char array compactly.
+void UniversalPrintArray(const char* begin, size_t len, ::std::ostream* os);
+
+// Prints an array of 'len' elements, starting at address 'begin', to a string.
+template <typename T>
+string UniversalPrintArrayToString(const T* begin, size_t len) {
+  ::std::stringstream ss;
+  UniversalPrintArray(begin, len, &ss);
+  return ss.str();
+}
+
 // Implements printing an array type T[N].
 template <typename T, size_t N>
 class UniversalPrinter<T[N]> {
@@ -587,41 +622,13 @@
   // Prints the given array, omitting some elements when there are too
   // many.
   static void Print(const T (&a)[N], ::std::ostream* os) {
-    // Prints a char array as a C string.  Note that we compare 'const
-    // T' with 'const char' instead of comparing T with char, in case
-    // that T is already a const type.
-    if (internal::type_equals<const T, const char>::value) {
-      UniversalPrinter<const T*>::Print(a, os);
-      return;
-    }
-
-    if (N == 0) {
-      *os << "{}";
-    } else {
-      *os << "{ ";
-      const size_t kThreshold = 18;
-      const size_t kChunkSize = 8;
-      // If the array has more than kThreshold elements, we'll have to
-      // omit some details by printing only the first and the last
-      // kChunkSize elements.
-      // TODO(wan): let the user control the threshold using a flag.
-      if (N <= kThreshold) {
-        PrintRawArrayTo(a, N, os);
-      } else {
-        PrintRawArrayTo(a, kChunkSize, os);
-        *os << ", ..., ";
-        PrintRawArrayTo(a + N - kChunkSize, kChunkSize, os);
-      }
-      *os << " }";
-    }
+    UniversalPrintArray(a, N, os);
   }
 
   // A convenient wrapper for Print() that returns the print-out as a
   // string.
   static string PrintToString(const T (&a)[N]) {
-    ::std::stringstream ss;
-    Print(a, &ss);
-    return ss.str();
+    return UniversalPrintArrayToString(a, N);
   }
 };
 
diff --git a/include/gmock/gmock-spec-builders.h b/include/gmock/gmock-spec-builders.h
index cc48bc0..d4578ac 100644
--- a/include/gmock/gmock-spec-builders.h
+++ b/include/gmock/gmock-spec-builders.h
@@ -93,10 +93,6 @@
 template <typename F>
 class FunctionMockerBase;
 
-// Helper class for implementing FunctionMockerBase<F>::InvokeWith().
-template <typename Result, typename F>
-class InvokeWithHelper;
-
 // Protects the mock object registry (in class Mock), all function
 // mockers, and all expectations.
 //
@@ -269,9 +265,6 @@
   template <typename F>
   friend class internal::FunctionMockerBase;
 
-  template <typename R, typename Args>
-  friend class internal::InvokeWithHelper;
-
   template <typename M>
   friend class NiceMock;
 
@@ -763,9 +756,6 @@
   template <typename Function>
   friend class FunctionMockerBase;
 
-  template <typename R, typename Function>
-  friend class InvokeWithHelper;
-
   // The following methods will be called only after the EXPECT_CALL()
   // statement finishes and when the current thread holds
   // g_gmock_mutex.
@@ -1042,6 +1032,78 @@
 #pragma warning(disable:4355)  // Temporarily disables warning 4355.
 #endif  // _MSV_VER
 
+// C++ treats the void type specially.  For example, you cannot define
+// a void-typed variable or pass a void value to a function.
+// ActionResultHolder<T> holds a value of type T, where T must be a
+// copyable type or void (T doesn't need to be default-constructable).
+// It hides the syntactic difference between void and other types, and
+// is used to unify the code for invoking both void-returning and
+// non-void-returning mock functions.  This generic definition is used
+// when T is not void.
+template <typename T>
+class ActionResultHolder {
+ public:
+  explicit ActionResultHolder(T value) : value_(value) {}
+
+  // The compiler-generated copy constructor and assignment operator
+  // are exactly what we need, so we don't need to define them.
+
+  T value() const { return value_; }
+
+  // Prints the held value as an action's result to os.
+  void PrintAsActionResult(::std::ostream* os) const {
+    *os << "\n          Returns: ";
+    UniversalPrinter<T>::Print(value_, os);
+  }
+
+  // Performs the given mock function's default action and returns the
+  // result in a ActionResultHolder.
+  template <typename Function, typename Arguments>
+  static ActionResultHolder PerformDefaultAction(
+      const FunctionMockerBase<Function>* func_mocker,
+      const Arguments& args,
+      const string& call_description) {
+    return ActionResultHolder(
+        func_mocker->PerformDefaultAction(args, call_description));
+  }
+
+  // Performs the given action and returns the result in a
+  // ActionResultHolder.
+  template <typename Function, typename Arguments>
+  static ActionResultHolder PerformAction(const Action<Function>& action,
+                                          const Arguments& args) {
+    return ActionResultHolder(action.Perform(args));
+  }
+
+ private:
+  T value_;
+};
+
+// Specialization for T = void.
+template <>
+class ActionResultHolder<void> {
+ public:
+  ActionResultHolder() {}
+  void value() const {}
+  void PrintAsActionResult(::std::ostream* /* os */) const {}
+
+  template <typename Function, typename Arguments>
+  static ActionResultHolder PerformDefaultAction(
+      const FunctionMockerBase<Function>* func_mocker,
+      const Arguments& args,
+      const string& call_description) {
+    func_mocker->PerformDefaultAction(args, call_description);
+    return ActionResultHolder();
+  }
+
+  template <typename Function, typename Arguments>
+  static ActionResultHolder PerformAction(const Action<Function>& action,
+                                          const Arguments& args) {
+    action.Perform(args);
+    return ActionResultHolder();
+  }
+};
+
 // The base of the function mocker class for the given function type.
 // We put the methods in this class instead of its child to avoid code
 // bloat.
@@ -1167,16 +1229,11 @@
   template <typename Function>
   friend class MockSpec;
 
-  template <typename R, typename Function>
-  friend class InvokeWithHelper;
-
   // Returns the result of invoking this mock function with the given
   // arguments.  This function can be safely called from multiple
   // threads concurrently.
   // L < g_gmock_mutex
-  Result InvokeWith(const ArgumentTuple& args) {
-    return InvokeWithHelper<Result, F>::InvokeAndPrintResult(this, args);
-  }
+  Result InvokeWith(const ArgumentTuple& args);
 
   // Adds and returns a default action spec for this mock function.
   // L < g_gmock_mutex
@@ -1417,170 +1474,109 @@
 // manner specified by 'reaction'.
 void ReportUninterestingCall(CallReaction reaction, const string& msg);
 
-// When an uninteresting or unexpected mock function is called, we
-// want to print its return value to assist the user debugging.  Since
-// there's nothing to print when the function returns void, we need to
-// specialize the logic of FunctionMockerBase<F>::InvokeWith() for
-// void return values.
-//
-// C++ doesn't allow us to specialize a member function template
-// unless we also specialize its enclosing class, so we had to let
-// InvokeWith() delegate its work to a helper class InvokeWithHelper,
-// which can then be specialized.
-//
-// Note that InvokeWithHelper must be a class template (as opposed to
-// a function template), as only class templates can be partially
-// specialized.
-template <typename Result, typename F>
-class InvokeWithHelper {
- public:
-  typedef typename Function<F>::ArgumentTuple ArgumentTuple;
-
-  // Calculates the result of invoking the function mocked by mocker
-  // with the given arguments, prints it, and returns it.
-  // L < g_gmock_mutex
-  static Result InvokeAndPrintResult(
-      FunctionMockerBase<F>* mocker,
-      const ArgumentTuple& args) {
-    if (mocker->expectations_.size() == 0) {
-      // No expectation is set on this mock method - we have an
-      // uninteresting call.
-
-      // Warns about the uninteresting call.
-      ::std::stringstream ss;
-      mocker->DescribeUninterestingCall(args, &ss);
-
-      // We must get Google Mock's reaction on uninteresting calls
-      // made on this mock object BEFORE performing the action,
-      // because the action may DELETE the mock object and make the
-      // following expression meaningless.
-      const CallReaction reaction =
-          Mock::GetReactionOnUninterestingCalls(mocker->MockObject());
-
-      // Calculates the function result.
-      Result result = mocker->PerformDefaultAction(args, ss.str());
-
-      // Prints the function result.
-      ss << "\n          Returns: ";
-      UniversalPrinter<Result>::Print(result, &ss);
-      ReportUninterestingCall(reaction, ss.str());
-
-      return result;
-    }
-
-    bool is_excessive = false;
-    ::std::stringstream ss;
-    ::std::stringstream why;
-    ::std::stringstream loc;
-    Action<F> action;
-    Expectation<F>* exp;
-
-    // The FindMatchingExpectationAndAction() function acquires and
-    // releases g_gmock_mutex.
-    const bool found = mocker->FindMatchingExpectationAndAction(
-        args, &exp, &action, &is_excessive, &ss, &why);
-    ss << "    Function call: " << mocker->Name();
-    UniversalPrinter<ArgumentTuple>::Print(args, &ss);
-    // In case the action deletes a piece of the expectation, we
-    // generate the message beforehand.
-    if (found && !is_excessive) {
-      exp->DescribeLocationTo(&loc);
-    }
-    Result result = action.IsDoDefault() ?
-        mocker->PerformDefaultAction(args, ss.str())
-        : action.Perform(args);
-    ss << "\n          Returns: ";
-    UniversalPrinter<Result>::Print(result, &ss);
-    ss << "\n" << why.str();
-
-    if (found) {
-      if (is_excessive) {
-        // We had an upper-bound violation and the failure message is in ss.
-        Expect(false, exp->file(), exp->line(), ss.str());
-      } else {
-        // We had an expected call and the matching expectation is
-        // described in ss.
-        Log(INFO, loc.str() + ss.str(), 3);
-      }
-    } else {
-      // No expectation matches this call - reports a failure.
-      Expect(false, NULL, -1, ss.str());
-    }
-    return result;
-  }
-};  // class InvokeWithHelper
-
-// This specialization helps to implement
-// FunctionMockerBase<F>::InvokeWith() for void-returning functions.
+// Calculates the result of invoking this mock function with the given
+// arguments, prints it, and returns it.
+// L < g_gmock_mutex
 template <typename F>
-class InvokeWithHelper<void, F> {
- public:
-  typedef typename Function<F>::ArgumentTuple ArgumentTuple;
+typename Function<F>::Result FunctionMockerBase<F>::InvokeWith(
+    const typename Function<F>::ArgumentTuple& args) {
+  typedef ActionResultHolder<Result> ResultHolder;
 
-  // Invokes the function mocked by mocker with the given arguments.
-  // L < g_gmock_mutex
-  static void InvokeAndPrintResult(FunctionMockerBase<F>* mocker,
-                                   const ArgumentTuple& args) {
-    const int count = static_cast<int>(mocker->expectations_.size());
-    if (count == 0) {
-      // No expectation is set on this mock method - we have an
-      // uninteresting call.
-      ::std::stringstream ss;
-      mocker->DescribeUninterestingCall(args, &ss);
+  if (expectations_.size() == 0) {
+    // No expectation is set on this mock method - we have an
+    // uninteresting call.
 
-      // We must get Google Mock's reaction on uninteresting calls
-      // made on this mock object BEFORE performing the action,
-      // because the action may DELETE the mock object and make the
-      // following expression meaningless.
-      const CallReaction reaction =
-          Mock::GetReactionOnUninterestingCalls(mocker->MockObject());
+    // We must get Google Mock's reaction on uninteresting calls
+    // made on this mock object BEFORE performing the action,
+    // because the action may DELETE the mock object and make the
+    // following expression meaningless.
+    const CallReaction reaction =
+        Mock::GetReactionOnUninterestingCalls(MockObject());
 
-      mocker->PerformDefaultAction(args, ss.str());
-      ReportUninterestingCall(reaction, ss.str());
-      return;
+    // True iff we need to print this call's arguments and return
+    // value.  This definition must be kept in sync with
+    // the behavior of ReportUninterestingCall().
+    const bool need_to_report_uninteresting_call =
+        // If the user allows this uninteresting call, we print it
+        // only when he wants informational messages.
+        reaction == ALLOW ? LogIsVisible(INFO) :
+        // If the user wants this to be a warning, we print it only
+        // when he wants to see warnings.
+        reaction == WARN ? LogIsVisible(WARNING) :
+        // Otherwise, the user wants this to be an error, and we
+        // should always print detailed information in the error.
+        true;
+
+    if (!need_to_report_uninteresting_call) {
+      // Perform the action without printing the call information.
+      return PerformDefaultAction(args, "");
     }
 
-    bool is_excessive = false;
+    // Warns about the uninteresting call.
     ::std::stringstream ss;
-    ::std::stringstream why;
-    ::std::stringstream loc;
-    Action<F> action;
-    Expectation<F>* exp;
+    DescribeUninterestingCall(args, &ss);
 
-    // The FindMatchingExpectationAndAction() function acquires and
-    // releases g_gmock_mutex.
-    const bool found = mocker->FindMatchingExpectationAndAction(
-        args, &exp, &action, &is_excessive, &ss, &why);
-    ss << "    Function call: " << mocker->Name();
-    UniversalPrinter<ArgumentTuple>::Print(args, &ss);
-    ss << "\n" << why.str();
-    // In case the action deletes a piece of the expectation, we
-    // generate the message beforehand.
-    if (found && !is_excessive) {
-      exp->DescribeLocationTo(&loc);
-    }
-    if (action.IsDoDefault()) {
-      mocker->PerformDefaultAction(args, ss.str());
-    } else {
-      action.Perform(args);
-    }
+    // Calculates the function result.
+    const ResultHolder result =
+        ResultHolder::PerformDefaultAction(this, args, ss.str());
 
-    if (found) {
-      // A matching expectation and corresponding action were found.
-      if (is_excessive) {
-        // We had an upper-bound violation and the failure message is in ss.
-        Expect(false, exp->file(), exp->line(), ss.str());
-      } else {
-        // We had an expected call and the matching expectation is
-        // described in ss.
-        Log(INFO, loc.str() + ss.str(), 3);
-      }
-    } else {
-      // No matching expectation was found - reports an error.
-      Expect(false, NULL, -1, ss.str());
-    }
+    // Prints the function result.
+    result.PrintAsActionResult(&ss);
+
+    ReportUninterestingCall(reaction, ss.str());
+    return result.value();
   }
-};  // class InvokeWithHelper<void, F>
+
+  bool is_excessive = false;
+  ::std::stringstream ss;
+  ::std::stringstream why;
+  ::std::stringstream loc;
+  Action<F> action;
+  Expectation<F>* exp;
+
+  // The FindMatchingExpectationAndAction() function acquires and
+  // releases g_gmock_mutex.
+  const bool found = FindMatchingExpectationAndAction(
+      args, &exp, &action, &is_excessive, &ss, &why);
+
+  // True iff we need to print the call's arguments and return value.
+  // This definition must be kept in sync with the uses of Expect()
+  // and Log() in this function.
+  const bool need_to_report_call = !found || is_excessive || LogIsVisible(INFO);
+  if (!need_to_report_call) {
+    // Perform the action without printing the call information.
+    return action.IsDoDefault() ? PerformDefaultAction(args, "") :
+        action.Perform(args);
+  }
+
+  ss << "    Function call: " << Name();
+  UniversalPrinter<ArgumentTuple>::Print(args, &ss);
+
+  // In case the action deletes a piece of the expectation, we
+  // generate the message beforehand.
+  if (found && !is_excessive) {
+    exp->DescribeLocationTo(&loc);
+  }
+
+  const ResultHolder result = action.IsDoDefault() ?
+      ResultHolder::PerformDefaultAction(this, args, ss.str()) :
+      ResultHolder::PerformAction(action, args);
+  result.PrintAsActionResult(&ss);
+  ss << "\n" << why.str();
+
+  if (!found) {
+    // No expectation matches this call - reports a failure.
+    Expect(false, NULL, -1, ss.str());
+  } else if (is_excessive) {
+    // We had an upper-bound violation and the failure message is in ss.
+    Expect(false, exp->file(), exp->line(), ss.str());
+  } else {
+    // We had an expected call and the matching expectation is
+    // described in ss.
+    Log(INFO, loc.str() + ss.str(), 2);
+  }
+  return result.value();
+}
 
 }  // namespace internal
 
diff --git a/include/gmock/internal/gmock-internal-utils.h b/include/gmock/internal/gmock-internal-utils.h
index b02682f..b5e38db 100644
--- a/include/gmock/internal/gmock-internal-utils.h
+++ b/include/gmock/internal/gmock-internal-utils.h
@@ -438,6 +438,10 @@
 // No logs are printed.
 const char kErrorVerbosity[] = "error";
 
+// Returns true iff a log with the given severity is visible according
+// to the --gmock_verbose flag.
+bool LogIsVisible(LogSeverity severity);
+
 // Prints the given message to stdout iff 'severity' >= the level
 // specified by the --gmock_verbose flag.  If stack_frames_to_skip >=
 // 0, also prints the stack trace excluding the top
diff --git a/scripts/gmock_doctor.py b/scripts/gmock_doctor.py
index 907089e..1980977 100755
--- a/scripts/gmock_doctor.py
+++ b/scripts/gmock_doctor.py
@@ -36,7 +36,7 @@
 import re
 import sys
 
-_VERSION = '1.0.0'
+_VERSION = '1.0.1'
 
 _COMMON_GMOCK_SYMBOLS = [
     # Matchers
@@ -46,8 +46,12 @@
     'AllOf',
     'An',
     'AnyOf',
+    'ContainerEq',
+    'Contains',
     'ContainsRegex',
     'DoubleEq',
+    'ElementsAre',
+    'ElementsAreArray',
     'EndsWith',
     'Eq',
     'Field',
@@ -60,6 +64,8 @@
     'Lt',
     'MatcherCast',
     'MatchesRegex',
+    'NanSensitiveDoubleEq',
+    'NanSensitiveFloatEq',
     'Ne',
     'Not',
     'NotNull',
@@ -67,6 +73,8 @@
     'PointeeIsInitializedProto',
     'Property',
     'Ref',
+    'ResultOf',
+    'SafeMatcherCast',
     'StartsWith',
     'StrCaseEq',
     'StrCaseNe',
@@ -76,7 +84,9 @@
     'TypedEq',
 
     # Actions
+    'Assign',
     'ByRef',
+    'DeleteArg',
     'DoAll',
     'DoDefault',
     'IgnoreResult',
@@ -84,11 +94,18 @@
     'InvokeArgument',
     'InvokeWithoutArgs',
     'Return',
+    'ReturnNew',
     'ReturnNull',
     'ReturnRef',
+    'SaveArg',
+    'SetArgReferee',
     'SetArgumentPointee',
     'SetArrayArgument',
+    'SetErrnoAndReturn',
+    'Throw',
+    'WithArg',
     'WithArgs',
+    'WithoutArgs',
 
     # Cardinalities
     'AnyNumber',
@@ -106,6 +123,9 @@
     'Mock',
     ]
 
+# Regex for matching source file path and line number in gcc's errors.
+_FILE_LINE_RE = r'(?P<file>.*):(?P<line>\d+):\s+'
+
 
 def _FindAllMatches(regex, s):
   """Generates all matches of regex in string s."""
@@ -128,6 +148,7 @@
       (short name of disease, long name of disease, diagnosis).
   """
 
+  diagnosis = '%(file)s:%(line)s:' + diagnosis
   for m in _FindAllMatches(regex, msg):
     yield (short_name, long_name, diagnosis % m.groupdict())
 
@@ -136,9 +157,9 @@
   """Diagnoses the NRR disease, given the error messages by gcc."""
 
   regex = (r'In member function \'testing::internal::ReturnAction<R>.*\n'
-           r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+           + _FILE_LINE_RE + r'instantiated from here\n'
            r'.*gmock-actions\.h.*error: creating array with negative size')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 You are using an Return() action in a function that returns a reference.
 Please use ReturnRef() instead."""
   return _GenericDiagnoser('NRR', 'Need to Return Reference',
@@ -148,11 +169,11 @@
 def _NeedToReturnSomethingDiagnoser(msg):
   """Diagnoses the NRS disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+):\s+'
+  regex = (_FILE_LINE_RE +
            r'(instantiated from here\n.'
            r'*gmock-actions\.h.*error: void value not ignored)'
            r'|(error: control reaches end of non-void function)')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 You are using an action that returns void, but it needs to return
 *something*.  Please tell it *what* to return.  Perhaps you can use
 the pattern DoAll(some_action, Return(some_value))?"""
@@ -163,10 +184,10 @@
 def _NeedToReturnNothingDiagnoser(msg):
   """Diagnoses the NRN disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+  regex = (_FILE_LINE_RE + r'instantiated from here\n'
            r'.*gmock-actions\.h.*error: return-statement with a value, '
            r'in function returning \'void\'')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 You are using an action that returns *something*, but it needs to return
 void.  Please use a void-returning action instead.
 
@@ -179,10 +200,10 @@
 def _IncompleteByReferenceArgumentDiagnoser(msg):
   """Diagnoses the IBRA disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+  regex = (_FILE_LINE_RE + r'instantiated from here\n'
            r'.*gmock-printers\.h.*error: invalid application of '
            r'\'sizeof\' to incomplete type \'(?P<type>.*)\'')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 In order to mock this function, Google Mock needs to see the definition
 of type "%(type)s" - declaration alone is not enough.  Either #include
 the header that defines it, or change the argument to be passed
@@ -194,9 +215,9 @@
 def _OverloadedFunctionMatcherDiagnoser(msg):
   """Diagnoses the OFM disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+): error: no matching function for '
+  regex = (_FILE_LINE_RE + r'error: no matching function for '
            r'call to \'Truly\(<unresolved overloaded function type>\)')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 The argument you gave to Truly() is an overloaded function.  Please tell
 gcc which overloaded version you want to use.
 
@@ -211,10 +232,9 @@
 def _OverloadedFunctionActionDiagnoser(msg):
   """Diagnoses the OFA disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+): error: '
-           r'no matching function for call to \'Invoke\('
+  regex = (_FILE_LINE_RE + r'error: no matching function for call to \'Invoke\('
            r'<unresolved overloaded function type>')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 You are passing an overloaded function to Invoke().  Please tell gcc
 which overloaded version you want to use.
 
@@ -229,10 +249,10 @@
 def _OverloadedMethodActionDiagnoser1(msg):
   """Diagnoses the OMA disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+): error: '
+  regex = (_FILE_LINE_RE + r'error: '
            r'.*no matching function for call to \'Invoke\(.*, '
            r'unresolved overloaded function type>')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 The second argument you gave to Invoke() is an overloaded method.  Please
 tell gcc which overloaded version you want to use.
 
@@ -250,10 +270,10 @@
 def _MockObjectPointerDiagnoser(msg):
   """Diagnoses the MOP disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+): error: request for member '
+  regex = (_FILE_LINE_RE + r'error: request for member '
            r'\'gmock_(?P<method>.+)\' in \'(?P<mock_object>.+)\', '
            r'which is of non-class type \'(.*::)*(?P<class_name>.+)\*\'')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 The first argument to ON_CALL() and EXPECT_CALL() must be a mock *object*,
 not a *pointer* to it.  Please write '*(%(mock_object)s)' instead of
 '%(mock_object)s' as your first argument.
@@ -279,9 +299,9 @@
 def _OverloadedMethodActionDiagnoser2(msg):
   """Diagnoses the OMA disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+): error: no matching function for '
+  regex = (_FILE_LINE_RE + r'error: no matching function for '
            r'call to \'Invoke\(.+, <unresolved overloaded function type>\)')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 The second argument you gave to Invoke() is an overloaded method.  Please
 tell gcc which overloaded version you want to use.
 
@@ -299,9 +319,9 @@
 def _NeedToUseSymbolDiagnoser(msg):
   """Diagnoses the NUS disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+): error: \'(?P<symbol>.+)\' '
+  regex = (_FILE_LINE_RE + r'error: \'(?P<symbol>.+)\' '
            r'(was not declared in this scope|has not been declared)')
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 '%(symbol)s' is defined by Google Mock in the testing namespace.
 Did you forget to write
   using testing::%(symbol)s;
@@ -315,11 +335,10 @@
 def _NeedToUseReturnNullDiagnoser(msg):
   """Diagnoses the NRNULL disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+):\s+instantiated from here\n'
+  regex = (_FILE_LINE_RE + r'instantiated from here\n'
            r'.*gmock-actions\.h.*error: invalid conversion from '
            r'\'long int\' to \'(?P<type>.+\*)')
-
-  diagnosis = """%(file)s:%(line)s:
+  diagnosis = """
 You are probably calling Return(NULL) and the compiler isn't sure how to turn
 NULL into a %(type)s*. Use ReturnNull() instead.
 Note: the line number may be off; please fix all instances of Return(NULL)."""
@@ -330,13 +349,11 @@
 def _WrongMockMethodMacroDiagnoser(msg):
   """Diagnoses the WMM disease, given the error messages by gcc."""
 
-  regex = (r'(?P<file>.*):(?P<line>\d+):\s+'
+  regex = (_FILE_LINE_RE +
            r'.*this_method_does_not_take_(?P<wrong_args>\d+)_argument.*\n'
            r'.*\n'
-           r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>'
-           )
-
-  diagnosis = """%(file)s:%(line)s:
+           r'.*candidates are.*FunctionMocker<[^>]+A(?P<args>\d+)\)>')
+  diagnosis = """
 You are using MOCK_METHOD%(wrong_args)s to define a mock method that has
 %(args)s arguments. Use MOCK_METHOD%(args)s (or MOCK_CONST_METHOD%(args)s,
 MOCK_METHOD%(args)s_T, MOCK_CONST_METHOD%(args)s_T as appropriate) instead."""
@@ -344,6 +361,21 @@
                            regex, diagnosis, msg)
 
 
+def _WrongParenPositionDiagnoser(msg):
+  """Diagnoses the WPP disease, given the error messages by gcc."""
+
+  regex = (_FILE_LINE_RE +
+           r'error:.*testing::internal::MockSpec<.* has no member named \''
+           r'(?P<method>\w+)\'')
+  diagnosis = """
+The closing parenthesis of ON_CALL or EXPECT_CALL should be *before*
+".%(method)s".  For example, you should write:
+  EXPECT_CALL(my_mock, Foo(_)).%(method)s(...);
+instead of:
+  EXPECT_CALL(my_mock, Foo(_).%(method)s(...));"""
+  return _GenericDiagnoser('WPP', 'Wrong parenthesis position',
+                           regex, diagnosis, msg)
+
 
 _DIAGNOSERS = [
     _IncompleteByReferenceArgumentDiagnoser,
@@ -358,6 +390,7 @@
     _OverloadedMethodActionDiagnoser1,
     _OverloadedMethodActionDiagnoser2,
     _WrongMockMethodMacroDiagnoser,
+    _WrongParenPositionDiagnoser,
     ]
 
 
diff --git a/src/gmock-internal-utils.cc b/src/gmock-internal-utils.cc
index 735abce..ce17d71 100644
--- a/src/gmock-internal-utils.cc
+++ b/src/gmock-internal-utils.cc
@@ -101,6 +101,22 @@
 // Protects global resources (stdout in particular) used by Log().
 static Mutex g_log_mutex(Mutex::NO_CONSTRUCTOR_NEEDED_FOR_STATIC_MUTEX);
 
+// Returns true iff a log with the given severity is visible according
+// to the --gmock_verbose flag.
+bool LogIsVisible(LogSeverity severity) {
+  if (GMOCK_FLAG(verbose) == kInfoVerbosity) {
+    // Always show the log if --gmock_verbose=info.
+    return true;
+  } else if (GMOCK_FLAG(verbose) == kErrorVerbosity) {
+    // Always hide it if --gmock_verbose=error.
+    return false;
+  } else {
+    // If --gmock_verbose is neither "info" nor "error", we treat it
+    // as "warning" (its default value).
+    return severity == WARNING;
+  }
+}
+
 // Prints the given message to stdout iff 'severity' >= the level
 // specified by the --gmock_verbose flag.  If stack_frames_to_skip >=
 // 0, also prints the stack trace excluding the top
@@ -110,17 +126,8 @@
 // conservative.
 void Log(LogSeverity severity, const string& message,
          int stack_frames_to_skip) {
-  if (GMOCK_FLAG(verbose) == kErrorVerbosity) {
-    // The user is not interested in logs.
+  if (!LogIsVisible(severity))
     return;
-  } else if (GMOCK_FLAG(verbose) != kInfoVerbosity) {
-    // The user is interested in warnings but not informational logs.
-    // Note that invalid values of GMOCK_FLAG(verbose) are treated as
-    // "warning", which is the default value of the flag.
-    if (severity == INFO) {
-      return;
-    }
-  }
 
   // Ensures that logs from different threads don't interleave.
   MutexLock l(&g_log_mutex);
diff --git a/src/gmock-printers.cc b/src/gmock-printers.cc
index e6d4001..922a7b2 100644
--- a/src/gmock-printers.cc
+++ b/src/gmock-printers.cc
@@ -242,6 +242,11 @@
   *os << "\"";
 }
 
+// Prints a (const) char array of 'len' elements, starting at address 'begin'.
+void UniversalPrintArray(const char* begin, size_t len, ostream* os) {
+  PrintCharsAsStringTo(begin, len, os);
+}
+
 // Prints the given array of wide characters to the ostream.
 // The array starts at *begin, the length is len, it may include L'\0'
 // characters and may not be null-terminated.
diff --git a/src/gmock-spec-builders.cc b/src/gmock-spec-builders.cc
index 65a74b8..465e4d6 100644
--- a/src/gmock-spec-builders.cc
+++ b/src/gmock-spec-builders.cc
@@ -139,10 +139,10 @@
 void ReportUninterestingCall(CallReaction reaction, const string& msg) {
   switch (reaction) {
     case ALLOW:
-      Log(INFO, msg, 4);
+      Log(INFO, msg, 3);
       break;
     case WARN:
-      Log(WARNING, msg, 4);
+      Log(WARNING, msg, 3);
       break;
     default:  // FAIL
       Expect(false, NULL, -1, msg);
diff --git a/test/gmock-internal-utils_test.cc b/test/gmock-internal-utils_test.cc
index 5e4dc03..7886f6d 100644
--- a/test/gmock-internal-utils_test.cc
+++ b/test/gmock-internal-utils_test.cc
@@ -494,6 +494,34 @@
   }, "Expectation failed");
 }
 
+// Tests LogIsVisible().
+
+class LogIsVisibleTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); }
+  virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; }
+
+  string original_verbose_;
+};
+
+TEST_F(LogIsVisibleTest, AlwaysReturnsTrueIfVerbosityIsInfo) {
+  GMOCK_FLAG(verbose) = kInfoVerbosity;
+  EXPECT_TRUE(LogIsVisible(INFO));
+  EXPECT_TRUE(LogIsVisible(WARNING));
+}
+
+TEST_F(LogIsVisibleTest, AlwaysReturnsFalseIfVerbosityIsError) {
+  GMOCK_FLAG(verbose) = kErrorVerbosity;
+  EXPECT_FALSE(LogIsVisible(INFO));
+  EXPECT_FALSE(LogIsVisible(WARNING));
+}
+
+TEST_F(LogIsVisibleTest, WorksWhenVerbosityIsWarning) {
+  GMOCK_FLAG(verbose) = kWarningVerbosity;
+  EXPECT_FALSE(LogIsVisible(INFO));
+  EXPECT_TRUE(LogIsVisible(WARNING));
+}
+
 // TODO(wan@google.com): find a way to re-enable these tests.
 #if 0
 
diff --git a/test/gmock-printers_test.cc b/test/gmock-printers_test.cc
index 29a0db8..f03be29 100644
--- a/test/gmock-printers_test.cc
+++ b/test/gmock-printers_test.cc
@@ -485,75 +485,58 @@
 
 // Tests printing C arrays.
 
-// One-dimensional array.
-
-void ArrayHelper1(int (&a)[5]) {  // NOLINT
-  EXPECT_EQ("{ 1, 2, 3, 4, 5 }", Print(a));
+// The difference between this and Print() is that it ensures that the
+// argument is a reference to an array.
+template <typename T, size_t N>
+string PrintArrayHelper(T (&a)[N]) {
+  return Print(a);
 }
 
+// One-dimensional array.
 TEST(PrintArrayTest, OneDimensionalArray) {
   int a[5] = { 1, 2, 3, 4, 5 };
-  ArrayHelper1(a);
+  EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a));
 }
 
 // Two-dimensional array.
-
-void ArrayHelper2(int (&a)[2][5]) {  // NOLINT
-  EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", Print(a));
-}
-
 TEST(PrintArrayTest, TwoDimensionalArray) {
   int a[2][5] = {
     { 1, 2, 3, 4, 5 },
     { 6, 7, 8, 9, 0 }
   };
-  ArrayHelper2(a);
+  EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a));
 }
 
 // Array of const elements.
-
-void ArrayHelper3(const bool (&a)[1]) {  // NOLINT
-  EXPECT_EQ("{ false }", Print(a));
-}
-
 TEST(PrintArrayTest, ConstArray) {
   const bool a[1] = { false };
-  ArrayHelper3(a);
+  EXPECT_EQ("{ false }", PrintArrayHelper(a));
 }
 
 // Char array.
-
-void ArrayHelper4(char (&a)[3]) {  // NOLINT
-  EXPECT_EQ(PrintPointer(a) + " pointing to \"Hi\"", Print(a));
-}
-
 TEST(PrintArrayTest, CharArray) {
-  char a[3] = "Hi";
-  ArrayHelper4(a);
+  // Array a contains '\0' in the middle and doesn't end with '\0'.
+  char a[3] = { 'H', '\0', 'i' };
+  EXPECT_EQ("\"H\\0i\"", PrintArrayHelper(a));
 }
 
 // Const char array.
-
-void ArrayHelper5(const char (&a)[3]) {  // NOLINT
-  EXPECT_EQ(Print(a), PrintPointer(a) + " pointing to \"Hi\"");
-}
-
 TEST(PrintArrayTest, ConstCharArray) {
-  const char a[3] = "Hi";
-  ArrayHelper5(a);
+  const char a[4] = "\0Hi";
+  EXPECT_EQ("\"\\0Hi\\0\"", PrintArrayHelper(a));
 }
 
 // Array of objects.
 TEST(PrintArrayTest, ObjectArray) {
   string a[3] = { "Hi", "Hello", "Ni hao" };
-  EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", Print(a));
+  EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a));
 }
 
 // Array with many elements.
 TEST(PrintArrayTest, BigArray) {
   int a[100] = { 1, 2, 3 };
   EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }",
-            Print(a));
+            PrintArrayHelper(a));
 }
 
 // Tests printing ::string and ::std::string.
@@ -995,6 +978,11 @@
             UniversalPrinter<const int&>::PrintToString(n));
 }
 
+TEST(PrintToStringTest, WorksForArray) {
+  int n[3] = { 1, 2, 3 };
+  EXPECT_EQ("{ 1, 2, 3 }", UniversalPrinter<int[3]>::PrintToString(n));
+}
+
 TEST(UniversalTersePrintTest, WorksForNonReference) {
   ::std::stringstream ss;
   UniversalTersePrint(123, &ss);
diff --git a/test/gmock-spec-builders_test.cc b/test/gmock-spec-builders_test.cc
index e8c3902..4711899 100644
--- a/test/gmock-spec-builders_test.cc
+++ b/test/gmock-spec-builders_test.cc
@@ -1612,6 +1612,53 @@
 
 #endif  // 0
 
+// A helper class that generates a failure when printed.  We use it to
+// ensure that Google Mock doesn't print a value (even to an internal
+// buffer) when it is not supposed to do so.
+class PrintMeNot {};
+
+void PrintTo(PrintMeNot /* dummy */, ::std::ostream* /* os */) {
+  ADD_FAILURE() << "Google Mock is printing a value that shouldn't be "
+                << "printed even to an internal buffer.";
+}
+
+class LogTestHelper {
+ public:
+  MOCK_METHOD1(Foo, PrintMeNot(PrintMeNot));
+};
+
+class GMockLogTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() { original_verbose_ = GMOCK_FLAG(verbose); }
+  virtual void TearDown() { GMOCK_FLAG(verbose) = original_verbose_; }
+
+  LogTestHelper helper_;
+  string original_verbose_;
+};
+
+TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsWarning) {
+  GMOCK_FLAG(verbose) = kWarningVerbosity;
+  EXPECT_CALL(helper_, Foo(_))
+      .WillOnce(Return(PrintMeNot()));
+  helper_.Foo(PrintMeNot());  // This is an expected call.
+}
+
+TEST_F(GMockLogTest, DoesNotPrintGoodCallInternallyIfVerbosityIsError) {
+  GMOCK_FLAG(verbose) = kErrorVerbosity;
+  EXPECT_CALL(helper_, Foo(_))
+      .WillOnce(Return(PrintMeNot()));
+  helper_.Foo(PrintMeNot());  // This is an expected call.
+}
+
+TEST_F(GMockLogTest, DoesNotPrintWarningInternallyIfVerbosityIsError) {
+  GMOCK_FLAG(verbose) = kErrorVerbosity;
+  ON_CALL(helper_, Foo(_))
+      .WillByDefault(Return(PrintMeNot()));
+  helper_.Foo(PrintMeNot());  // This should generate a warning.
+}
+
+// Tests Mock::AllowLeak().
+
 TEST(AllowLeakTest, AllowsLeakingUnusedMockObject) {
   MockA* a = new MockA;
   Mock::AllowLeak(a);