Bug Summary

File:tools/clang/lib/Format/FormatToken.cpp
Warning:line 186, column 12
Access to field 'HasUnescapedNewline' results in a dereference of a null pointer (loaded from variable 'ItemBegin')

Annotated Source Code

1//===--- FormatToken.cpp - Format C++ code --------------------------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9///
10/// \file
11/// \brief This file implements specific functions of \c FormatTokens and their
12/// roles.
13///
14//===----------------------------------------------------------------------===//
15
16#include "FormatToken.h"
17#include "ContinuationIndenter.h"
18#include "llvm/ADT/SmallVector.h"
19#include "llvm/Support/Debug.h"
20#include <climits>
21
22namespace clang {
23namespace format {
24
25const char *getTokenTypeName(TokenType Type) {
26 static const char *const TokNames[] = {
27#define TYPE(X) #X,
28LIST_TOKEN_TYPESTYPE(ArrayInitializerLSquare) TYPE(ArraySubscriptLSquare) TYPE
(AttributeParen) TYPE(BinaryOperator) TYPE(BitFieldColon) TYPE
(BlockComment) TYPE(CastRParen) TYPE(ConditionalExpr) TYPE(ConflictAlternative
) TYPE(ConflictEnd) TYPE(ConflictStart) TYPE(CtorInitializerColon
) TYPE(CtorInitializerComma) TYPE(DesignatedInitializerPeriod
) TYPE(DictLiteral) TYPE(ForEachMacro) TYPE(FunctionAnnotationRParen
) TYPE(FunctionDeclarationName) TYPE(FunctionLBrace) TYPE(FunctionTypeLParen
) TYPE(ImplicitStringLiteral) TYPE(InheritanceColon) TYPE(InheritanceComma
) TYPE(InlineASMBrace) TYPE(InlineASMColon) TYPE(JavaAnnotation
) TYPE(JsComputedPropertyName) TYPE(JsExponentiation) TYPE(JsExponentiationEqual
) TYPE(JsFatArrow) TYPE(JsNonNullAssertion) TYPE(JsTypeColon)
TYPE(JsTypeOperator) TYPE(JsTypeOptionalQuestion) TYPE(LambdaArrow
) TYPE(LambdaLSquare) TYPE(LeadingJavaAnnotation) TYPE(LineComment
) TYPE(MacroBlockBegin) TYPE(MacroBlockEnd) TYPE(ObjCBlockLBrace
) TYPE(ObjCBlockLParen) TYPE(ObjCDecl) TYPE(ObjCForIn) TYPE(ObjCMethodExpr
) TYPE(ObjCMethodSpecifier) TYPE(ObjCProperty) TYPE(ObjCStringLiteral
) TYPE(OverloadedOperator) TYPE(OverloadedOperatorLParen) TYPE
(PointerOrReference) TYPE(PureVirtualSpecifier) TYPE(RangeBasedForLoopColon
) TYPE(RegexLiteral) TYPE(SelectorName) TYPE(StartOfName) TYPE
(TemplateCloser) TYPE(TemplateOpener) TYPE(TemplateString) TYPE
(TrailingAnnotation) TYPE(TrailingReturnArrow) TYPE(TrailingUnaryOperator
) TYPE(UnaryOperator) TYPE(Unknown)
29#undef TYPE
30 nullptr
31 };
32
33 if (Type < NUM_TOKEN_TYPES)
34 return TokNames[Type];
35 llvm_unreachable("unknown TokenType")::llvm::llvm_unreachable_internal("unknown TokenType", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Format/FormatToken.cpp"
, 35)
;
36 return nullptr;
37}
38
39// FIXME: This is copy&pasted from Sema. Put it in a common place and remove
40// duplication.
41bool FormatToken::isSimpleTypeSpecifier() const {
42 switch (Tok.getKind()) {
43 case tok::kw_short:
44 case tok::kw_long:
45 case tok::kw___int64:
46 case tok::kw___int128:
47 case tok::kw_signed:
48 case tok::kw_unsigned:
49 case tok::kw_void:
50 case tok::kw_char:
51 case tok::kw_int:
52 case tok::kw_half:
53 case tok::kw_float:
54 case tok::kw_double:
55 case tok::kw___float128:
56 case tok::kw_wchar_t:
57 case tok::kw_bool:
58 case tok::kw___underlying_type:
59 case tok::annot_typename:
60 case tok::kw_char16_t:
61 case tok::kw_char32_t:
62 case tok::kw_typeof:
63 case tok::kw_decltype:
64 return true;
65 default:
66 return false;
67 }
68}
69
70TokenRole::~TokenRole() {}
71
72void TokenRole::precomputeFormattingInfos(const FormatToken *Token) {}
73
74unsigned CommaSeparatedList::formatAfterToken(LineState &State,
75 ContinuationIndenter *Indenter,
76 bool DryRun) {
77 if (State.NextToken == nullptr || !State.NextToken->Previous)
78 return 0;
79
80 if (Formats.size() == 1)
81 return 0; // Handled by formatFromToken
82
83 // Ensure that we start on the opening brace.
84 const FormatToken *LBrace =
85 State.NextToken->Previous->getPreviousNonComment();
86 if (!LBrace || !LBrace->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare) ||
87 LBrace->BlockKind == BK_Block || LBrace->Type == TT_DictLiteral ||
88 LBrace->Next->Type == TT_DesignatedInitializerPeriod)
89 return 0;
90
91 // Calculate the number of code points we have to format this list. As the
92 // first token is already placed, we have to subtract it.
93 unsigned RemainingCodePoints =
94 Style.ColumnLimit - State.Column + State.NextToken->Previous->ColumnWidth;
95
96 // Find the best ColumnFormat, i.e. the best number of columns to use.
97 const ColumnFormat *Format = getColumnFormat(RemainingCodePoints);
98
99 // If no ColumnFormat can be used, the braced list would generally be
100 // bin-packed. Add a severe penalty to this so that column layouts are
101 // preferred if possible.
102 if (!Format)
103 return 10000;
104
105 // Format the entire list.
106 unsigned Penalty = 0;
107 unsigned Column = 0;
108 unsigned Item = 0;
109 while (State.NextToken != LBrace->MatchingParen) {
110 bool NewLine = false;
111 unsigned ExtraSpaces = 0;
112
113 // If the previous token was one of our commas, we are now on the next item.
114 if (Item < Commas.size() && State.NextToken->Previous == Commas[Item]) {
115 if (!State.NextToken->isTrailingComment()) {
116 ExtraSpaces += Format->ColumnSizes[Column] - ItemLengths[Item];
117 ++Column;
118 }
119 ++Item;
120 }
121
122 if (Column == Format->Columns || State.NextToken->MustBreakBefore) {
123 Column = 0;
124 NewLine = true;
125 }
126
127 // Place token using the continuation indenter and store the penalty.
128 Penalty += Indenter->addTokenToState(State, NewLine, DryRun, ExtraSpaces);
129 }
130 return Penalty;
131}
132
133unsigned CommaSeparatedList::formatFromToken(LineState &State,
134 ContinuationIndenter *Indenter,
135 bool DryRun) {
136 // Formatting with 1 Column isn't really a column layout, so we don't need the
137 // special logic here. We can just avoid bin packing any of the parameters.
138 if (Formats.size() == 1 || HasNestedBracedList)
139 State.Stack.back().AvoidBinPacking = true;
140 return 0;
141}
142
143// Returns the lengths in code points between Begin and End (both included),
144// assuming that the entire sequence is put on a single line.
145static unsigned CodePointsBetween(const FormatToken *Begin,
146 const FormatToken *End) {
147 assert(End->TotalLength >= Begin->TotalLength)((End->TotalLength >= Begin->TotalLength) ? static_cast
<void> (0) : __assert_fail ("End->TotalLength >= Begin->TotalLength"
, "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Format/FormatToken.cpp"
, 147, __PRETTY_FUNCTION__))
;
148 return End->TotalLength - Begin->TotalLength + Begin->ColumnWidth;
149}
150
151void CommaSeparatedList::precomputeFormattingInfos(const FormatToken *Token) {
152 // FIXME: At some point we might want to do this for other lists, too.
153 if (!Token->MatchingParen ||
1
Assuming the condition is false
2
Taking false branch
154 !Token->isOneOf(tok::l_brace, TT_ArrayInitializerLSquare))
155 return;
156
157 // In C++11 braced list style, we should not format in columns unless they
158 // have many items (20 or more) or we allow bin-packing of function call
159 // arguments.
160 if (Style.Cpp11BracedListStyle && !Style.BinPackArguments &&
3
Assuming the condition is false
161 Commas.size() < 19)
162 return;
163
164 // Limit column layout for JavaScript array initializers to 20 or more items
165 // for now to introduce it carefully. We can become more aggressive if this
166 // necessary.
167 if (Token->is(TT_ArrayInitializerLSquare) && Commas.size() < 19)
4
Assuming the condition is false
5
Taking false branch
168 return;
169
170 // Column format doesn't really make sense if we don't align after brackets.
171 if (Style.AlignAfterOpenBracket == FormatStyle::BAS_DontAlign)
6
Assuming the condition is false
7
Taking false branch
172 return;
173
174 FormatToken *ItemBegin = Token->Next;
175 while (ItemBegin->isTrailingComment())
8
Loop condition is false. Execution continues on line 177
176 ItemBegin = ItemBegin->Next;
177 SmallVector<bool, 8> MustBreakBeforeItem;
178
179 // The lengths of an item if it is put at the end of the line. This includes
180 // trailing comments which are otherwise ignored for column alignment.
181 SmallVector<unsigned, 8> EndOfLineItemLength;
182
183 bool HasSeparatingComment = false;
184 for (unsigned i = 0, e = Commas.size() + 1; i != e; ++i) {
9
Assuming 'i' is not equal to 'e'
10
Loop condition is true. Entering loop body
18
Assuming 'i' is not equal to 'e'
19
Loop condition is true. Entering loop body
185 // Skip comments on their own line.
186 while (ItemBegin->HasUnescapedNewline && ItemBegin->isTrailingComment()) {
11
Assuming the condition is false
20
Access to field 'HasUnescapedNewline' results in a dereference of a null pointer (loaded from variable 'ItemBegin')
187 ItemBegin = ItemBegin->Next;
188 HasSeparatingComment = i > 0;
189 }
190
191 MustBreakBeforeItem.push_back(ItemBegin->MustBreakBefore);
192 if (ItemBegin->is(tok::l_brace))
12
Taking false branch
193 HasNestedBracedList = true;
194 const FormatToken *ItemEnd = nullptr;
195 if (i == Commas.size()) {
13
Assuming the condition is false
14
Taking false branch
196 ItemEnd = Token->MatchingParen;
197 const FormatToken *NonCommentEnd = ItemEnd->getPreviousNonComment();
198 ItemLengths.push_back(CodePointsBetween(ItemBegin, NonCommentEnd));
199 if (Style.Cpp11BracedListStyle &&
200 !ItemEnd->Previous->isTrailingComment()) {
201 // In Cpp11 braced list style, the } and possibly other subsequent
202 // tokens will need to stay on a line with the last element.
203 while (ItemEnd->Next && !ItemEnd->Next->CanBreakBefore)
204 ItemEnd = ItemEnd->Next;
205 } else {
206 // In other braced lists styles, the "}" can be wrapped to the new line.
207 ItemEnd = Token->MatchingParen->Previous;
208 }
209 } else {
210 ItemEnd = Commas[i];
211 // The comma is counted as part of the item when calculating the length.
212 ItemLengths.push_back(CodePointsBetween(ItemBegin, ItemEnd));
213
214 // Consume trailing comments so the are included in EndOfLineItemLength.
215 if (ItemEnd->Next && !ItemEnd->Next->HasUnescapedNewline &&
15
Assuming pointer value is null
216 ItemEnd->Next->isTrailingComment())
217 ItemEnd = ItemEnd->Next;
218 }
219 EndOfLineItemLength.push_back(CodePointsBetween(ItemBegin, ItemEnd));
220 // If there is a trailing comma in the list, the next item will start at the
221 // closing brace. Don't create an extra item for this.
222 if (ItemEnd->getNextNonComment() == Token->MatchingParen)
16
Taking false branch
223 break;
224 ItemBegin = ItemEnd->Next;
17
Null pointer value stored to 'ItemBegin'
225 }
226
227 // Don't use column layout for lists with few elements and in presence of
228 // separating comments.
229 if (Commas.size() < 5 || HasSeparatingComment)
230 return;
231
232 if (Token->NestingLevel != 0 && Token->is(tok::l_brace) && Commas.size() < 19)
233 return;
234
235 // We can never place more than ColumnLimit / 3 items in a row (because of the
236 // spaces and the comma).
237 unsigned MaxItems = Style.ColumnLimit / 3;
238 std::vector<unsigned> MinSizeInColumn;
239 MinSizeInColumn.reserve(MaxItems);
240 for (unsigned Columns = 1; Columns <= MaxItems; ++Columns) {
241 ColumnFormat Format;
242 Format.Columns = Columns;
243 Format.ColumnSizes.resize(Columns);
244 MinSizeInColumn.assign(Columns, UINT_MAX(2147483647 *2U +1U));
245 Format.LineCount = 1;
246 bool HasRowWithSufficientColumns = false;
247 unsigned Column = 0;
248 for (unsigned i = 0, e = ItemLengths.size(); i != e; ++i) {
249 assert(i < MustBreakBeforeItem.size())((i < MustBreakBeforeItem.size()) ? static_cast<void>
(0) : __assert_fail ("i < MustBreakBeforeItem.size()", "/tmp/buildd/llvm-toolchain-snapshot-5.0~svn303373/tools/clang/lib/Format/FormatToken.cpp"
, 249, __PRETTY_FUNCTION__))
;
250 if (MustBreakBeforeItem[i] || Column == Columns) {
251 ++Format.LineCount;
252 Column = 0;
253 }
254 if (Column == Columns - 1)
255 HasRowWithSufficientColumns = true;
256 unsigned Length =
257 (Column == Columns - 1) ? EndOfLineItemLength[i] : ItemLengths[i];
258 Format.ColumnSizes[Column] = std::max(Format.ColumnSizes[Column], Length);
259 MinSizeInColumn[Column] = std::min(MinSizeInColumn[Column], Length);
260 ++Column;
261 }
262 // If all rows are terminated early (e.g. by trailing comments), we don't
263 // need to look further.
264 if (!HasRowWithSufficientColumns)
265 break;
266 Format.TotalWidth = Columns - 1; // Width of the N-1 spaces.
267
268 for (unsigned i = 0; i < Columns; ++i)
269 Format.TotalWidth += Format.ColumnSizes[i];
270
271 // Don't use this Format, if the difference between the longest and shortest
272 // element in a column exceeds a threshold to avoid excessive spaces.
273 if ([&] {
274 for (unsigned i = 0; i < Columns - 1; ++i)
275 if (Format.ColumnSizes[i] - MinSizeInColumn[i] > 10)
276 return true;
277 return false;
278 }())
279 continue;
280
281 // Ignore layouts that are bound to violate the column limit.
282 if (Format.TotalWidth > Style.ColumnLimit && Columns > 1)
283 continue;
284
285 Formats.push_back(Format);
286 }
287}
288
289const CommaSeparatedList::ColumnFormat *
290CommaSeparatedList::getColumnFormat(unsigned RemainingCharacters) const {
291 const ColumnFormat *BestFormat = nullptr;
292 for (SmallVector<ColumnFormat, 4>::const_reverse_iterator
293 I = Formats.rbegin(),
294 E = Formats.rend();
295 I != E; ++I) {
296 if (I->TotalWidth <= RemainingCharacters || I->Columns == 1) {
297 if (BestFormat && I->LineCount > BestFormat->LineCount)
298 break;
299 BestFormat = &*I;
300 }
301 }
302 return BestFormat;
303}
304
305} // namespace format
306} // namespace clang