Coverage Report

Created: 2022-01-25 06:29

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Format/TokenAnnotator.h
Line
Count
Source (jump to first uncovered line)
1
//===--- TokenAnnotator.h - Format C++ code ---------------------*- C++ -*-===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
///
9
/// \file
10
/// This file implements a token annotator, i.e. creates
11
/// \c AnnotatedTokens out of \c FormatTokens with required extra information.
12
///
13
//===----------------------------------------------------------------------===//
14
15
#ifndef LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
16
#define LLVM_CLANG_LIB_FORMAT_TOKENANNOTATOR_H
17
18
#include "UnwrappedLineParser.h"
19
#include "clang/Format/Format.h"
20
21
namespace clang {
22
namespace format {
23
24
enum LineType {
25
  LT_Invalid,
26
  LT_ImportStatement,
27
  LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
28
  LT_ObjCMethodDecl,
29
  LT_ObjCProperty, // An @property line.
30
  LT_Other,
31
  LT_PreprocessorDirective,
32
  LT_VirtualFunctionDecl,
33
  LT_ArrayOfStructInitializer,
34
};
35
36
class AnnotatedLine {
37
public:
38
  AnnotatedLine(const UnwrappedLine &Line)
39
      : First(Line.Tokens.front().Tok), Level(Line.Level),
40
        MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex),
41
        MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex),
42
        InPPDirective(Line.InPPDirective),
43
        MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
44
        IsMultiVariableDeclStmt(false), Affected(false),
45
        LeadingEmptyLinesAffected(false), ChildrenAffected(false),
46
198k
        FirstStartColumn(Line.FirstStartColumn) {
47
198k
    assert(!Line.Tokens.empty());
48
49
    // Calculate Next and Previous for all tokens. Note that we must overwrite
50
    // Next and Previous for every token, as previous formatting runs might have
51
    // left them in a different state.
52
0
    First->Previous = nullptr;
53
198k
    FormatToken *Current = First;
54
648k
    for (const UnwrappedLineNode &Node : llvm::drop_begin(Line.Tokens)) {
55
648k
      Current->Next = Node.Tok;
56
648k
      Node.Tok->Previous = Current;
57
648k
      Current = Current->Next;
58
648k
      Current->Children.clear();
59
648k
      for (const auto &Child : Node.Children) {
60
3.45k
        Children.push_back(new AnnotatedLine(Child));
61
3.45k
        Current->Children.push_back(Children.back());
62
3.45k
      }
63
648k
    }
64
198k
    Last = Current;
65
198k
    Last->Next = nullptr;
66
198k
  }
67
68
198k
  ~AnnotatedLine() {
69
201k
    for (unsigned i = 0, e = Children.size(); i != e; 
++i3.45k
) {
70
3.45k
      delete Children[i];
71
3.45k
    }
72
198k
    FormatToken *Current = First;
73
1.06M
    while (Current) {
74
867k
      Current->Children.clear();
75
867k
      Current->Role.reset();
76
867k
      Current = Current->Next;
77
867k
    }
78
198k
  }
79
80
  /// \c true if this line starts with the given tokens in order, ignoring
81
  /// comments.
82
1.33M
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
1.33M
    return First && First->startsSequence(Tokens...);
84
1.33M
  }
bool clang::format::AnnotatedLine::startsWith<clang::tok::TokenKind>(clang::tok::TokenKind) const
Line
Count
Source
82
470k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
470k
    return First && First->startsSequence(Tokens...);
84
470k
  }
bool clang::format::AnnotatedLine::startsWith<clang::format::TokenType>(clang::format::TokenType) const
Line
Count
Source
82
844k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
844k
    return First && First->startsSequence(Tokens...);
84
844k
  }
bool clang::format::AnnotatedLine::startsWith<clang::tok::TokenKind, clang::tok::TokenKind>(clang::tok::TokenKind, clang::tok::TokenKind) const
Line
Count
Source
82
15.0k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
15.0k
    return First && First->startsSequence(Tokens...);
84
15.0k
  }
bool clang::format::AnnotatedLine::startsWith<clang::IdentifierInfo*, clang::tok::TokenKind>(clang::IdentifierInfo*, clang::tok::TokenKind) const
Line
Count
Source
82
3.94k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
3.94k
    return First && First->startsSequence(Tokens...);
84
3.94k
  }
bool clang::format::AnnotatedLine::startsWith<clang::tok::TokenKind, clang::IdentifierInfo*, clang::tok::TokenKind>(clang::tok::TokenKind, clang::IdentifierInfo*, clang::tok::TokenKind) const
Line
Count
Source
82
3.88k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
3.88k
    return First && First->startsSequence(Tokens...);
84
3.88k
  }
bool clang::format::AnnotatedLine::startsWith<clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind>(clang::tok::TokenKind, clang::tok::TokenKind, clang::tok::TokenKind) const
Line
Count
Source
82
486
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
486
    return First && First->startsSequence(Tokens...);
84
486
  }
bool clang::format::AnnotatedLine::startsWith<clang::IdentifierInfo*>(clang::IdentifierInfo*) const
Line
Count
Source
82
62
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
83
62
    return First && First->startsSequence(Tokens...);
84
62
  }
85
86
  /// \c true if this line ends with the given tokens in reversed order,
87
  /// ignoring comments.
88
  /// For example, given tokens [T1, T2, T3, ...], the function returns true if
89
  /// this line is like "... T3 T2 T1".
90
8.41k
  template <typename... Ts> bool endsWith(Ts... Tokens) const {
91
8.41k
    return Last && Last->endsSequence(Tokens...);
92
8.41k
  }
93
94
  /// \c true if this line looks like a function definition instead of a
95
  /// function declaration. Asserts MightBeFunctionDecl.
96
6.23k
  bool mightBeFunctionDefinition() const {
97
6.23k
    assert(MightBeFunctionDecl);
98
    // Try to determine if the end of a stream of tokens is either the
99
    // Definition or the Declaration for a function. It does this by looking for
100
    // the ';' in foo(); and using that it ends with a ; to know this is the
101
    // Definition, however the line could end with
102
    //    foo(); /* comment */
103
    // or
104
    //    foo(); // comment
105
    // or
106
    //    foo() // comment
107
    // endsWith() ignores the comment.
108
0
    return !endsWith(tok::semi);
109
6.23k
  }
110
111
  /// \c true if this line starts a namespace definition.
112
8.30k
  bool startsWithNamespace() const {
113
8.30k
    return startsWith(tok::kw_namespace) || 
startsWith(TT_NamespaceMacro)7.06k
||
114
8.30k
           
startsWith(tok::kw_inline, tok::kw_namespace)7.04k
||
115
8.30k
           
startsWith(tok::kw_export, tok::kw_namespace)7.02k
;
116
8.30k
  }
117
118
  FormatToken *First;
119
  FormatToken *Last;
120
121
  SmallVector<AnnotatedLine *, 0> Children;
122
123
  LineType Type;
124
  unsigned Level;
125
  size_t MatchingOpeningBlockLineIndex;
126
  size_t MatchingClosingBlockLineIndex;
127
  bool InPPDirective;
128
  bool MustBeDeclaration;
129
  bool MightBeFunctionDecl;
130
  bool IsMultiVariableDeclStmt;
131
132
  /// \c True if this line should be formatted, i.e. intersects directly or
133
  /// indirectly with one of the input ranges.
134
  bool Affected;
135
136
  /// \c True if the leading empty lines of this line intersect with one of the
137
  /// input ranges.
138
  bool LeadingEmptyLinesAffected;
139
140
  /// \c True if one of this line's children intersects with an input range.
141
  bool ChildrenAffected;
142
143
  unsigned FirstStartColumn;
144
145
private:
146
  // Disallow copying.
147
  AnnotatedLine(const AnnotatedLine &) = delete;
148
  void operator=(const AnnotatedLine &) = delete;
149
};
150
151
/// Determines extra information about the tokens comprising an
152
/// \c UnwrappedLine.
153
class TokenAnnotator {
154
public:
155
  TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
156
50.7k
      : Style(Style), Keywords(Keywords) {}
157
158
  /// Adapts the indent levels of comment lines to the indent of the
159
  /// subsequent line.
160
  // FIXME: Can/should this be done in the UnwrappedLineParser?
161
  void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines);
162
163
  void annotate(AnnotatedLine &Line);
164
  void calculateFormattingInformation(AnnotatedLine &Line);
165
166
private:
167
  /// Calculate the penalty for splitting before \c Tok.
168
  unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,
169
                        bool InFunctionDecl);
170
171
  bool spaceRequiredBeforeParens(const FormatToken &Right) const;
172
173
  bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
174
                            const FormatToken &Right);
175
176
  bool spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right);
177
178
  bool mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
179
180
  bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
181
182
  bool mustBreakForReturnType(const AnnotatedLine &Line) const;
183
184
  void printDebugInfo(const AnnotatedLine &Line);
185
186
  void calculateUnbreakableTailLengths(AnnotatedLine &Line);
187
188
  void calculateArrayInitializerColumnList(AnnotatedLine &Line);
189
190
  FormatToken *calculateInitializerColumnList(AnnotatedLine &Line,
191
                                              FormatToken *CurrentToken,
192
                                              unsigned Depth);
193
  FormatStyle::PointerAlignmentStyle
194
  getTokenReferenceAlignment(const FormatToken &PointerOrReference);
195
196
  FormatStyle::PointerAlignmentStyle
197
  getTokenPointerOrReferenceAlignment(const FormatToken &PointerOrReference);
198
199
  const FormatStyle &Style;
200
201
  const AdditionalKeywords &Keywords;
202
};
203
204
} // end namespace format
205
} // end namespace clang
206
207
#endif