~ubuntu-branches/ubuntu/trusty/llvm-toolchain-snapshot/trusty-201310232150

« back to all changes in this revision

Viewing changes to clang/lib/Format/WhitespaceManager.cpp

  • Committer: Package Import Robot
  • Author(s): Sylvestre Ledru
  • Date: 2013-05-27 15:01:57 UTC
  • mfrom: (0.10.1) (0.9.1) (0.8.1) (0.7.1) (0.6.1) (0.5.2)
  • Revision ID: package-import@ubuntu.com-20130527150157-tdkrsjpuvht7v0qx
Tags: 1:3.4~svn182733-1~exp1
* New snapshot release (3.4 release)
* Add a symlink of libLLVM-3.4.so.1 to usr/lib/llvm-3.4/lib/libLLVM-3.4.so
    to fix make the llvm-config-3.4 --libdir work (Closes: #708677)
  * Various packages rename to allow co installations:
    * libclang1 => libclang1-3.4
    * libclang1-dbg => libclang1-3.4-dbg
    * libclang-dev => libclang-3.4-dev
    * libclang-common-dev => libclang-common-3.4-dev

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
namespace clang {
19
19
namespace format {
20
20
 
 
21
bool
 
22
WhitespaceManager::Change::IsBeforeInFile::operator()(const Change &C1,
 
23
                                                      const Change &C2) const {
 
24
  return SourceMgr.isBeforeInTranslationUnit(
 
25
      C1.OriginalWhitespaceRange.getBegin(),
 
26
      C2.OriginalWhitespaceRange.getBegin());
 
27
}
 
28
 
 
29
WhitespaceManager::Change::Change(
 
30
    bool CreateReplacement, const SourceRange &OriginalWhitespaceRange,
 
31
    unsigned Spaces, unsigned StartOfTokenColumn, unsigned NewlinesBefore,
 
32
    StringRef PreviousLinePostfix, StringRef CurrentLinePrefix,
 
33
    tok::TokenKind Kind, bool ContinuesPPDirective)
 
34
    : CreateReplacement(CreateReplacement),
 
35
      OriginalWhitespaceRange(OriginalWhitespaceRange),
 
36
      StartOfTokenColumn(StartOfTokenColumn), NewlinesBefore(NewlinesBefore),
 
37
      PreviousLinePostfix(PreviousLinePostfix),
 
38
      CurrentLinePrefix(CurrentLinePrefix), Kind(Kind),
 
39
      ContinuesPPDirective(ContinuesPPDirective), Spaces(Spaces) {}
 
40
 
21
41
void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok,
22
 
                                          unsigned NewLines, unsigned Spaces,
23
 
                                          unsigned WhitespaceStartColumn) {
24
 
  // 2+ newlines mean an empty line separating logic scopes.
25
 
  if (NewLines >= 2)
26
 
    alignComments();
 
42
                                          unsigned Newlines, unsigned Spaces,
 
43
                                          unsigned StartOfTokenColumn,
 
44
                                          bool InPPDirective) {
 
45
  Changes.push_back(Change(
 
46
      true, Tok.FormatTok.WhitespaceRange,
 
47
      Spaces, StartOfTokenColumn, Newlines, "", "", Tok.FormatTok.Tok.getKind(),
 
48
      InPPDirective && !Tok.FormatTok.IsFirst));
27
49
 
28
50
  // Align line comments if they are trailing or if they continue other
29
51
  // trailing comments.
 
52
  // FIXME: Pull this out and generalize so it works the same way in broken
 
53
  // comments and unbroken comments with trailing whitespace.
30
54
  if (Tok.isTrailingComment()) {
31
55
    SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace()
32
56
        .getLocWithOffset(Tok.FormatTok.TokenLength);
34
58
    if (Tok.FormatTok.TrailingWhiteSpaceLength != 0)
35
59
      Replaces.insert(tooling::Replacement(
36
60
          SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, ""));
37
 
 
38
 
    bool LineExceedsColumnLimit =
39
 
        Spaces + WhitespaceStartColumn + Tok.FormatTok.TokenLength >
40
 
        Style.ColumnLimit;
41
 
    // Align comment with other comments.
42
 
    if ((Tok.Parent != NULL || !Comments.empty()) && !LineExceedsColumnLimit) {
43
 
      StoredComment Comment;
44
 
      Comment.Tok = Tok.FormatTok;
45
 
      Comment.Spaces = Spaces;
46
 
      Comment.NewLines = NewLines;
47
 
      Comment.MinColumn =
48
 
          NewLines > 0 ? Spaces : WhitespaceStartColumn + Spaces;
49
 
      Comment.MaxColumn = Style.ColumnLimit - Tok.FormatTok.TokenLength;
50
 
      Comment.Untouchable = false;
51
 
      Comments.push_back(Comment);
52
 
      return;
53
 
    }
54
61
  }
55
 
 
56
 
  // If this line does not have a trailing comment, align the stored comments.
57
 
  if (Tok.Children.empty() && !Tok.isTrailingComment())
58
 
    alignComments();
59
 
 
60
 
  storeReplacement(Tok.FormatTok, getNewLineText(NewLines, Spaces));
61
62
}
62
63
 
63
 
void WhitespaceManager::replacePPWhitespace(const AnnotatedToken &Tok,
64
 
                                            unsigned NewLines, unsigned Spaces,
65
 
                                            unsigned WhitespaceStartColumn) {
66
 
  storeReplacement(Tok.FormatTok,
67
 
                   getNewLineText(NewLines, Spaces, WhitespaceStartColumn));
 
64
void WhitespaceManager::addUntouchableToken(const FormatToken &Tok,
 
65
                                            bool InPPDirective) {
 
66
  Changes.push_back(
 
67
      Change(false, Tok.WhitespaceRange, /*Spaces=*/0,
 
68
             SourceMgr.getSpellingColumnNumber(Tok.Tok.getLocation()) - 1,
 
69
             Tok.NewlinesBefore, "", "", Tok.Tok.getKind(),
 
70
             InPPDirective && !Tok.IsFirst));
68
71
}
69
72
 
70
73
void WhitespaceManager::breakToken(const FormatToken &Tok, unsigned Offset,
71
 
                                   unsigned ReplaceChars, StringRef Prefix,
72
 
                                   StringRef Postfix, bool InPPDirective,
73
 
                                   unsigned Spaces,
74
 
                                   unsigned WhitespaceStartColumn) {
75
 
  std::string NewLineText;
76
 
  if (!InPPDirective)
77
 
    NewLineText = getNewLineText(1, Spaces);
78
 
  else
79
 
    NewLineText = getNewLineText(1, Spaces, WhitespaceStartColumn);
80
 
  std::string ReplacementText = (Prefix + NewLineText + Postfix).str();
81
 
  SourceLocation Location =
82
 
      Tok.getStartOfNonWhitespace().getLocWithOffset(Offset);
83
 
  Replaces.insert(
84
 
      tooling::Replacement(SourceMgr, Location, ReplaceChars, ReplacementText));
85
 
}
86
 
 
87
 
const tooling::Replacements &WhitespaceManager::generateReplacements() {
88
 
  alignComments();
89
 
  return Replaces;
 
74
                                   unsigned ReplaceChars,
 
75
                                   StringRef PreviousPostfix,
 
76
                                   StringRef CurrentPrefix, bool InPPDirective,
 
77
                                   unsigned Spaces) {
 
78
  Changes.push_back(Change(
 
79
      true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
 
80
                        Tok.getStartOfNonWhitespace().getLocWithOffset(
 
81
                            Offset + ReplaceChars)),
 
82
      Spaces, Spaces, 1, PreviousPostfix, CurrentPrefix,
 
83
      // FIXME: Unify token adjustment, so we don't split it between
 
84
      // BreakableToken and the WhitespaceManager. That would also allow us to
 
85
      // correctly store a tok::TokenKind instead of rolling our own enum.
 
86
      tok::unknown, InPPDirective && !Tok.IsFirst));
90
87
}
91
88
 
92
89
void WhitespaceManager::addReplacement(const SourceLocation &SourceLoc,
95
92
      tooling::Replacement(SourceMgr, SourceLoc, ReplaceChars, Text));
96
93
}
97
94
 
98
 
void WhitespaceManager::addUntouchableComment(unsigned Column) {
99
 
  StoredComment Comment;
100
 
  Comment.MinColumn = Column;
101
 
  Comment.MaxColumn = Column;
102
 
  Comment.Untouchable = true;
103
 
  Comments.push_back(Comment);
 
95
const tooling::Replacements &WhitespaceManager::generateReplacements() {
 
96
  if (Changes.empty())
 
97
    return Replaces;
 
98
 
 
99
  std::sort(Changes.begin(), Changes.end(), Change::IsBeforeInFile(SourceMgr));
 
100
  calculateLineBreakInformation();
 
101
  alignTrailingComments();
 
102
  alignEscapedNewlines();
 
103
  generateChanges();
 
104
 
 
105
  return Replaces;
 
106
}
 
107
 
 
108
void WhitespaceManager::calculateLineBreakInformation() {
 
109
  Changes[0].PreviousEndOfTokenColumn = 0;
 
110
  for (unsigned i = 1, e = Changes.size(); i != e; ++i) {
 
111
    unsigned OriginalWhitespaceStart =
 
112
        SourceMgr.getFileOffset(Changes[i].OriginalWhitespaceRange.getBegin());
 
113
    unsigned PreviousOriginalWhitespaceEnd = SourceMgr.getFileOffset(
 
114
        Changes[i - 1].OriginalWhitespaceRange.getEnd());
 
115
    Changes[i - 1].TokenLength =
 
116
        OriginalWhitespaceStart - PreviousOriginalWhitespaceEnd +
 
117
        Changes[i].PreviousLinePostfix.size() +
 
118
        Changes[i - 1].CurrentLinePrefix.size();
 
119
 
 
120
    Changes[i].PreviousEndOfTokenColumn =
 
121
        Changes[i - 1].StartOfTokenColumn + Changes[i - 1].TokenLength;
 
122
 
 
123
    Changes[i - 1].IsTrailingComment =
 
124
        (Changes[i].NewlinesBefore > 0 || Changes[i].Kind == tok::eof) &&
 
125
        Changes[i - 1].Kind == tok::comment;
 
126
  }
 
127
  // FIXME: The last token is currently not always an eof token; in those
 
128
  // cases, setting TokenLength of the last token to 0 is wrong.
 
129
  Changes.back().TokenLength = 0;
 
130
  Changes.back().IsTrailingComment = Changes.back().Kind == tok::comment;
 
131
}
 
132
 
 
133
void WhitespaceManager::alignTrailingComments() {
 
134
  unsigned MinColumn = 0;
 
135
  unsigned MaxColumn = UINT_MAX;
 
136
  unsigned StartOfSequence = 0;
 
137
  bool BreakBeforeNext = false;
 
138
  unsigned Newlines = 0;
 
139
  for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
 
140
    unsigned ChangeMinColumn = Changes[i].StartOfTokenColumn;
 
141
    // FIXME: Correctly handle ChangeMaxColumn in PP directives.
 
142
    unsigned ChangeMaxColumn = Style.ColumnLimit - Changes[i].TokenLength;
 
143
    Newlines += Changes[i].NewlinesBefore;
 
144
    if (Changes[i].IsTrailingComment) {
 
145
      bool WasAlignedWithStartOfNextLine =
 
146
          // A comment on its own line.
 
147
          Changes[i].NewlinesBefore == 1 &&
 
148
          // Not the last line.
 
149
          i + 1 != e &&
 
150
          // The start of the next token was previously aligned with
 
151
          // the start of this comment.
 
152
          (SourceMgr.getSpellingColumnNumber(
 
153
               Changes[i].OriginalWhitespaceRange.getEnd()) ==
 
154
           SourceMgr.getSpellingColumnNumber(
 
155
               Changes[i + 1].OriginalWhitespaceRange.getEnd())) &&
 
156
          // Which is not a comment itself.
 
157
          Changes[i + 1].Kind != tok::comment;
 
158
      if (BreakBeforeNext || Newlines > 1 ||
 
159
          (ChangeMinColumn > MaxColumn || ChangeMaxColumn < MinColumn) ||
 
160
          // Break the comment sequence if the previous line did not end
 
161
          // in a trailing comment.
 
162
          (Changes[i].NewlinesBefore == 1 && i > 0 &&
 
163
           !Changes[i - 1].IsTrailingComment) ||
 
164
          WasAlignedWithStartOfNextLine) {
 
165
        alignTrailingComments(StartOfSequence, i, MinColumn);
 
166
        MinColumn = ChangeMinColumn;
 
167
        MaxColumn = ChangeMaxColumn;
 
168
        StartOfSequence = i;
 
169
      } else {
 
170
        MinColumn = std::max(MinColumn, ChangeMinColumn);
 
171
        MaxColumn = std::min(MaxColumn, ChangeMaxColumn);
 
172
      }
 
173
      BreakBeforeNext =
 
174
          (i == 0) || (Changes[i].NewlinesBefore > 1) ||
 
175
          // Never start a sequence with a comment at the beginning of
 
176
          // the line.
 
177
          (Changes[i].NewlinesBefore == 1 && StartOfSequence == i);
 
178
      Newlines = 0;
 
179
    }
 
180
  }
 
181
  alignTrailingComments(StartOfSequence, Changes.size(), MinColumn);
 
182
}
 
183
 
 
184
void WhitespaceManager::alignTrailingComments(unsigned Start, unsigned End,
 
185
                                              unsigned Column) {
 
186
  for (unsigned i = Start; i != End; ++i) {
 
187
    if (Changes[i].IsTrailingComment) {
 
188
      assert(Column >= Changes[i].StartOfTokenColumn);
 
189
      Changes[i].Spaces += Column - Changes[i].StartOfTokenColumn;
 
190
      Changes[i].StartOfTokenColumn = Column;
 
191
    }
 
192
  }
 
193
}
 
194
 
 
195
void WhitespaceManager::alignEscapedNewlines() {
 
196
  unsigned MaxEndOfLine = 0;
 
197
  unsigned StartOfMacro = 0;
 
198
  for (unsigned i = 1, e = Changes.size(); i < e; ++i) {
 
199
    Change &C = Changes[i];
 
200
    if (C.NewlinesBefore > 0) {
 
201
      if (C.ContinuesPPDirective) {
 
202
        if (Style.AlignEscapedNewlinesLeft)
 
203
          MaxEndOfLine = std::max(C.PreviousEndOfTokenColumn + 2, MaxEndOfLine);
 
204
        else
 
205
          MaxEndOfLine = Style.ColumnLimit;
 
206
      } else {
 
207
        alignEscapedNewlines(StartOfMacro + 1, i, MaxEndOfLine);
 
208
        MaxEndOfLine = 0;
 
209
        StartOfMacro = i;
 
210
      }
 
211
    }
 
212
  }
 
213
  alignEscapedNewlines(StartOfMacro + 1, Changes.size(), MaxEndOfLine);
 
214
}
 
215
 
 
216
void WhitespaceManager::alignEscapedNewlines(unsigned Start, unsigned End,
 
217
                                             unsigned Column) {
 
218
  for (unsigned i = Start; i < End; ++i) {
 
219
    Change &C = Changes[i];
 
220
    if (C.NewlinesBefore > 0) {
 
221
      assert(C.ContinuesPPDirective);
 
222
      if (C.PreviousEndOfTokenColumn + 1 > Column)
 
223
        C.EscapedNewlineColumn = 0;
 
224
      else
 
225
        C.EscapedNewlineColumn = Column;
 
226
    }
 
227
  }
 
228
}
 
229
 
 
230
void WhitespaceManager::generateChanges() {
 
231
  for (unsigned i = 0, e = Changes.size(); i != e; ++i) {
 
232
    const Change &C = Changes[i];
 
233
    if (C.CreateReplacement) {
 
234
      std::string ReplacementText =
 
235
          C.PreviousLinePostfix +
 
236
          (C.ContinuesPPDirective
 
237
               ? getNewLineText(C.NewlinesBefore, C.Spaces,
 
238
                                C.PreviousEndOfTokenColumn,
 
239
                                C.EscapedNewlineColumn)
 
240
               : getNewLineText(C.NewlinesBefore, C.Spaces)) +
 
241
          C.CurrentLinePrefix;
 
242
      storeReplacement(C.OriginalWhitespaceRange, ReplacementText);
 
243
    }
 
244
  }
 
245
}
 
246
 
 
247
void WhitespaceManager::storeReplacement(const SourceRange &Range,
 
248
                                         StringRef Text) {
 
249
  unsigned WhitespaceLength = SourceMgr.getFileOffset(Range.getEnd()) -
 
250
                              SourceMgr.getFileOffset(Range.getBegin());
 
251
  // Don't create a replacement, if it does not change anything.
 
252
  if (StringRef(SourceMgr.getCharacterData(Range.getBegin()),
 
253
                WhitespaceLength) ==
 
254
      Text)
 
255
    return;
 
256
  Replaces.insert(tooling::Replacement(
 
257
      SourceMgr, CharSourceRange::getCharRange(Range), Text));
104
258
}
105
259
 
106
260
std::string WhitespaceManager::getNewLineText(unsigned NewLines,
107
261
                                              unsigned Spaces) {
108
 
  return std::string(NewLines, '\n') + std::string(Spaces, ' ');
 
262
  return std::string(NewLines, '\n') + getIndentText(Spaces);
109
263
}
110
264
 
111
265
std::string WhitespaceManager::getNewLineText(unsigned NewLines,
112
266
                                              unsigned Spaces,
113
 
                                              unsigned WhitespaceStartColumn) {
 
267
                                              unsigned PreviousEndOfTokenColumn,
 
268
                                              unsigned EscapedNewlineColumn) {
114
269
  std::string NewLineText;
115
270
  if (NewLines > 0) {
116
271
    unsigned Offset =
117
 
        std::min<int>(Style.ColumnLimit - 1, WhitespaceStartColumn);
 
272
        std::min<int>(EscapedNewlineColumn - 1, PreviousEndOfTokenColumn);
118
273
    for (unsigned i = 0; i < NewLines; ++i) {
119
 
      NewLineText += std::string(Style.ColumnLimit - Offset - 1, ' ');
 
274
      NewLineText += std::string(EscapedNewlineColumn - Offset - 1, ' ');
120
275
      NewLineText += "\\\n";
121
276
      Offset = 0;
122
277
    }
123
278
  }
124
 
  return NewLineText + std::string(Spaces, ' ');
125
 
}
126
 
 
127
 
void WhitespaceManager::alignComments() {
128
 
  unsigned MinColumn = 0;
129
 
  unsigned MaxColumn = UINT_MAX;
130
 
  comment_iterator Start = Comments.begin();
131
 
  for (comment_iterator I = Start, E = Comments.end(); I != E; ++I) {
132
 
    if (I->MinColumn > MaxColumn || I->MaxColumn < MinColumn) {
133
 
      alignComments(Start, I, MinColumn);
134
 
      MinColumn = I->MinColumn;
135
 
      MaxColumn = I->MaxColumn;
136
 
      Start = I;
137
 
    } else {
138
 
      MinColumn = std::max(MinColumn, I->MinColumn);
139
 
      MaxColumn = std::min(MaxColumn, I->MaxColumn);
140
 
    }
141
 
  }
142
 
  alignComments(Start, Comments.end(), MinColumn);
143
 
  Comments.clear();
144
 
}
145
 
 
146
 
void WhitespaceManager::alignComments(comment_iterator I, comment_iterator E,
147
 
                                      unsigned Column) {
148
 
  while (I != E) {
149
 
    if (!I->Untouchable) {
150
 
      unsigned Spaces = I->Spaces + Column - I->MinColumn;
151
 
      storeReplacement(I->Tok, getNewLineText(I->NewLines, Spaces));
152
 
    }
153
 
    ++I;
154
 
  }
155
 
}
156
 
 
157
 
void WhitespaceManager::storeReplacement(const FormatToken &Tok,
158
 
                                         const std::string Text) {
159
 
  // Don't create a replacement, if it does not change anything.
160
 
  if (StringRef(SourceMgr.getCharacterData(Tok.WhiteSpaceStart),
161
 
                Tok.WhiteSpaceLength) == Text)
162
 
    return;
163
 
 
164
 
  Replaces.insert(tooling::Replacement(SourceMgr, Tok.WhiteSpaceStart,
165
 
                                       Tok.WhiteSpaceLength, Text));
 
279
  return NewLineText + getIndentText(Spaces);
 
280
}
 
281
 
 
282
std::string WhitespaceManager::getIndentText(unsigned Spaces) {
 
283
  if (!Style.UseTab)
 
284
    return std::string(Spaces, ' ');
 
285
 
 
286
  return std::string(Spaces / Style.IndentWidth, '\t') +
 
287
         std::string(Spaces % Style.IndentWidth, ' ');
166
288
}
167
289
 
168
290
} // namespace format