Indentation fixes for clang-format.

- Fix behavior of memoization together with optimization
- Correctly attribute the PenaltyIndentLevel (breaking directly after "(" did
  not count towards the inner level)
- Recognize more tokens as assignments

Review: http://llvm-reviews.chandlerc.com/D172

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@169384 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Format/Format.cpp b/lib/Format/Format.cpp
index 7845046..030e35e 100644
--- a/lib/Format/Format.cpp
+++ b/lib/Format/Format.cpp
@@ -28,10 +28,18 @@
 
 // FIXME: Move somewhere sane.
 struct TokenAnnotation {
-  enum TokenType { TT_Unknown, TT_TemplateOpener, TT_TemplateCloser,
-      TT_BinaryOperator, TT_UnaryOperator, TT_OverloadedOperator,
-      TT_PointerOrReference, TT_ConditionalExpr, TT_LineComment,
-      TT_BlockComment };
+  enum TokenType {
+    TT_Unknown,
+    TT_TemplateOpener,
+    TT_TemplateCloser,
+    TT_BinaryOperator,
+    TT_UnaryOperator,
+    TT_OverloadedOperator,
+    TT_PointerOrReference,
+    TT_ConditionalExpr,
+    TT_LineComment,
+    TT_BlockComment
+  };
 
   TokenType Type;
 
@@ -85,7 +93,6 @@
 
   void format() {
     unsigned Indent = formatFirstToken();
-    count = 0;
     IndentState State;
     State.Column = Indent + Line.Tokens[0].Tok.getLength();
     State.CtorInitializerOnNewLine = false;
@@ -230,9 +237,6 @@
     ++State.ConsumedTokens;
   }
 
-  typedef std::map<IndentState, unsigned> StateMap;
-  StateMap Memory;
-
   unsigned splitPenalty(const FormatToken &Token) {
     if (Token.Tok.is(tok::semi))
       return 0;
@@ -272,36 +276,41 @@
     if (NewLine && State.InCtorInitializer && !State.CtorInitializerOnNewLine)
       return UINT_MAX;
 
+    unsigned CurrentPenalty = 0;
+    if (NewLine) {
+      CurrentPenalty += Parameters.PenaltyIndentLevel * State.Indent.size() +
+          Parameters.PenaltyExtraLine +
+          splitPenalty(Line.Tokens[State.ConsumedTokens - 1]);
+    }
+
     addTokenToState(NewLine, true, State);
 
     // Exceeding column limit is bad.
     if (State.Column > Style.ColumnLimit)
       return UINT_MAX;
 
-    unsigned CurrentPenalty = 0;
-    if (NewLine) {
-      CurrentPenalty += Parameters.PenaltyIndentLevel * State.Indent.size() +
-          Parameters.PenaltyExtraLine +
-          splitPenalty(Line.Tokens[State.ConsumedTokens - 2]);
-    }
-
     if (StopAt <= CurrentPenalty)
       return UINT_MAX;
     StopAt -= CurrentPenalty;
 
-    // Has this state already been examined?
     StateMap::iterator I = Memory.find(State);
-    if (I != Memory.end())
-      return I->second;
-    ++count;
+    if (I != Memory.end()) {
+      // If this state has already been examined, we can safely return the
+      // previous result if we
+      // - have not hit the optimatization (and thus returned UINT_MAX) OR
+      // - are now computing for a smaller or equal StopAt.
+      unsigned SavedResult = I->second.first;
+      unsigned SavedStopAt = I->second.second;
+      if (SavedResult != UINT_MAX || StopAt <= SavedStopAt)
+        return SavedResult;
+    }
 
     unsigned NoBreak = calcPenalty(State, false, StopAt);
     unsigned WithBreak = calcPenalty(State, true, std::min(StopAt, NoBreak));
     unsigned Result = std::min(NoBreak, WithBreak);
     if (Result != UINT_MAX)
       Result += CurrentPenalty;
-    Memory[State] = Result;
-    assert(Memory.find(State) != Memory.end());
+    Memory[State] = std::pair<unsigned, unsigned>(Result, StopAt);
     return Result;
   }
 
@@ -340,9 +349,12 @@
   const UnwrappedLine &Line;
   const std::vector<TokenAnnotation> &Annotations;
   tooling::Replacements &Replaces;
-  unsigned int count;
   bool StructuralError;
 
+  // A map from an indent state to a pair (Result, Used-StopAt).
+  typedef std::map<IndentState, std::pair<unsigned, unsigned> > StateMap;
+  StateMap Memory;
+
   OptimizationParameters Parameters;
 };
 
@@ -548,16 +560,18 @@
 
 private:
   void determineTokenTypes() {
-    bool EqualEncountered = false;
+    bool AssignmentEncountered = false;
     for (int i = 0, e = Line.Tokens.size(); i != e; ++i) {
       TokenAnnotation &Annotation = Annotations[i];
       const FormatToken &Tok = Line.Tokens[i];
 
-      if (Tok.Tok.is(tok::equal))
-        EqualEncountered = true;
+      if (Tok.Tok.is(tok::equal) || Tok.Tok.is(tok::plusequal) ||
+          Tok.Tok.is(tok::minusequal) || Tok.Tok.is(tok::starequal) ||
+          Tok.Tok.is(tok::slashequal))
+        AssignmentEncountered = true;
 
       if (Tok.Tok.is(tok::star) || Tok.Tok.is(tok::amp))
-        Annotation.Type = determineStarAmpUsage(i, EqualEncountered);
+        Annotation.Type = determineStarAmpUsage(i, AssignmentEncountered);
       else if (isUnaryOperator(i))
         Annotation.Type = TokenAnnotation::TT_UnaryOperator;
       else if (isBinaryOperator(Line.Tokens[i]))
@@ -605,7 +619,7 @@
   }
 
   TokenAnnotation::TokenType determineStarAmpUsage(unsigned Index,
-                                                   bool EqualEncountered) {
+                                                   bool AssignmentEncountered) {
     if (Index == Annotations.size())
       return TokenAnnotation::TT_Unknown;
 
@@ -620,7 +634,7 @@
 
     // It is very unlikely that we are going to find a pointer or reference type
     // definition on the RHS of an assignment.
-    if (EqualEncountered)
+    if (AssignmentEncountered)
       return TokenAnnotation::TT_BinaryOperator;
 
     return TokenAnnotation::TT_PointerOrReference;
@@ -676,8 +690,9 @@
       return false;
     if (isBinaryOperator(Left))
       return true;
-    return Right.Tok.is(tok::colon) || Left.Tok.is(tok::comma) || Left.Tok.is(
-        tok::semi) || Left.Tok.is(tok::equal) || Left.Tok.is(tok::ampamp) ||
+    return Right.Tok.is(tok::colon) || Left.Tok.is(tok::comma) ||
+        Left.Tok.is(tok::semi) || Left.Tok.is(tok::equal) ||
+        Left.Tok.is(tok::ampamp) || Left.Tok.is(tok::pipepipe) ||
         (Left.Tok.is(tok::l_paren) && !Right.Tok.is(tok::r_paren));
   }