Coverage Report

Created: 2020-02-18 08:44

/Users/buildslave/jenkins/workspace/coverage/llvm-project/clang/lib/Format/TokenAnnotator.h
Line
Count
Source
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
class SourceManager;
23
24
namespace format {
25
26
enum LineType {
27
  LT_Invalid,
28
  LT_ImportStatement,
29
  LT_ObjCDecl, // An @interface, @implementation, or @protocol line.
30
  LT_ObjCMethodDecl,
31
  LT_ObjCProperty, // An @property line.
32
  LT_Other,
33
  LT_PreprocessorDirective,
34
  LT_VirtualFunctionDecl
35
};
36
37
class AnnotatedLine {
38
public:
39
  AnnotatedLine(const UnwrappedLine &Line)
40
      : First(Line.Tokens.front().Tok), Level(Line.Level),
41
        MatchingOpeningBlockLineIndex(Line.MatchingOpeningBlockLineIndex),
42
        MatchingClosingBlockLineIndex(Line.MatchingClosingBlockLineIndex),
43
        InPPDirective(Line.InPPDirective),
44
        MustBeDeclaration(Line.MustBeDeclaration), MightBeFunctionDecl(false),
45
        IsMultiVariableDeclStmt(false), Affected(false),
46
        LeadingEmptyLinesAffected(false), ChildrenAffected(false),
47
133k
        FirstStartColumn(Line.FirstStartColumn) {
48
133k
    assert(!Line.Tokens.empty());
49
133k
50
133k
    // Calculate Next and Previous for all tokens. Note that we must overwrite
51
133k
    // Next and Previous for every token, as previous formatting runs might have
52
133k
    // left them in a different state.
53
133k
    First->Previous = nullptr;
54
133k
    FormatToken *Current = First;
55
133k
    for (std::list<UnwrappedLineNode>::const_iterator I = ++Line.Tokens.begin(),
56
133k
                                                      E = Line.Tokens.end();
57
567k
         I != E; 
++I433k
) {
58
433k
      const UnwrappedLineNode &Node = *I;
59
433k
      Current->Next = I->Tok;
60
433k
      I->Tok->Previous = Current;
61
433k
      Current = Current->Next;
62
433k
      Current->Children.clear();
63
433k
      for (const auto &Child : Node.Children) {
64
2.86k
        Children.push_back(new AnnotatedLine(Child));
65
2.86k
        Current->Children.push_back(Children.back());
66
2.86k
      }
67
433k
    }
68
133k
    Last = Current;
69
133k
    Last->Next = nullptr;
70
133k
  }
71
72
133k
  ~AnnotatedLine() {
73
136k
    for (unsigned i = 0, e = Children.size(); i != e; 
++i2.86k
) {
74
2.86k
      delete Children[i];
75
2.86k
    }
76
133k
    FormatToken *Current = First;
77
715k
    while (Current) {
78
582k
      Current->Children.clear();
79
582k
      Current->Role.reset();
80
582k
      Current = Current->Next;
81
582k
    }
82
133k
  }
83
84
  /// \c true if this line starts with the given tokens in order, ignoring
85
  /// comments.
86
925k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
87
925k
    return First && First->startsSequence(Tokens...);
88
925k
  }
bool clang::format::AnnotatedLine::startsWith<clang::tok::TokenKind>(clang::tok::TokenKind) const
Line
Count
Source
86
333k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
87
333k
    return First && First->startsSequence(Tokens...);
88
333k
  }
bool clang::format::AnnotatedLine::startsWith<clang::format::TokenType>(clang::format::TokenType) const
Line
Count
Source
86
565k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
87
565k
    return First && First->startsSequence(Tokens...);
88
565k
  }
bool clang::format::AnnotatedLine::startsWith<clang::tok::TokenKind, clang::tok::TokenKind>(clang::tok::TokenKind, clang::tok::TokenKind) const
Line
Count
Source
86
18.6k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
87
18.6k
    return First && First->startsSequence(Tokens...);
88
18.6k
  }
bool clang::format::AnnotatedLine::startsWith<clang::IdentifierInfo*, clang::tok::TokenKind>(clang::IdentifierInfo*, clang::tok::TokenKind) const
Line
Count
Source
86
3.63k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
87
3.63k
    return First && First->startsSequence(Tokens...);
88
3.63k
  }
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
86
3.57k
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
87
3.57k
    return First && First->startsSequence(Tokens...);
88
3.57k
  }
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
86
454
  template <typename... Ts> bool startsWith(Ts... Tokens) const {
87
454
    return First && First->startsSequence(Tokens...);
88
454
  }
89
90
  /// \c true if this line ends with the given tokens in reversed order,
91
  /// ignoring comments.
92
  /// For example, given tokens [T1, T2, T3, ...], the function returns true if
93
  /// this line is like "... T3 T2 T1".
94
195
  template <typename... Ts> bool endsWith(Ts... Tokens) const {
95
195
    return Last && Last->endsSequence(Tokens...);
96
195
  }
97
98
  /// \c true if this line looks like a function definition instead of a
99
  /// function declaration. Asserts MightBeFunctionDecl.
100
162
  bool mightBeFunctionDefinition() const {
101
162
    assert(MightBeFunctionDecl);
102
162
    // Try to determine if the end of a stream of tokens is either the
103
162
    // Definition or the Declaration for a function. It does this by looking for
104
162
    // the ';' in foo(); and using that it ends with a ; to know this is the
105
162
    // Definition, however the line could end with
106
162
    //    foo(); /* comment */
107
162
    // or
108
162
    //    foo(); // comment
109
162
    // or
110
162
    //    foo() // comment
111
162
    // endsWith() ignores the comment.
112
162
    return !endsWith(tok::semi);
113
162
  }
114
115
  /// \c true if this line starts a namespace definition.
116
5.25k
  bool startsWithNamespace() const {
117
5.25k
    return startsWith(tok::kw_namespace) || 
startsWith(TT_NamespaceMacro)4.24k
||
118
5.25k
           
startsWith(tok::kw_inline, tok::kw_namespace)4.21k
||
119
5.25k
           
startsWith(tok::kw_export, tok::kw_namespace)4.20k
;
120
5.25k
  }
121
122
  FormatToken *First;
123
  FormatToken *Last;
124
125
  SmallVector<AnnotatedLine *, 0> Children;
126
127
  LineType Type;
128
  unsigned Level;
129
  size_t MatchingOpeningBlockLineIndex;
130
  size_t MatchingClosingBlockLineIndex;
131
  bool InPPDirective;
132
  bool MustBeDeclaration;
133
  bool MightBeFunctionDecl;
134
  bool IsMultiVariableDeclStmt;
135
136
  /// \c True if this line should be formatted, i.e. intersects directly or
137
  /// indirectly with one of the input ranges.
138
  bool Affected;
139
140
  /// \c True if the leading empty lines of this line intersect with one of the
141
  /// input ranges.
142
  bool LeadingEmptyLinesAffected;
143
144
  /// \c True if one of this line's children intersects with an input range.
145
  bool ChildrenAffected;
146
147
  unsigned FirstStartColumn;
148
149
private:
150
  // Disallow copying.
151
  AnnotatedLine(const AnnotatedLine &) = delete;
152
  void operator=(const AnnotatedLine &) = delete;
153
};
154
155
/// Determines extra information about the tokens comprising an
156
/// \c UnwrappedLine.
157
class TokenAnnotator {
158
public:
159
  TokenAnnotator(const FormatStyle &Style, const AdditionalKeywords &Keywords)
160
33.0k
      : Style(Style), Keywords(Keywords) {}
161
162
  /// Adapts the indent levels of comment lines to the indent of the
163
  /// subsequent line.
164
  // FIXME: Can/should this be done in the UnwrappedLineParser?
165
  void setCommentLineLevels(SmallVectorImpl<AnnotatedLine *> &Lines);
166
167
  void annotate(AnnotatedLine &Line);
168
  void calculateFormattingInformation(AnnotatedLine &Line);
169
170
private:
171
  /// Calculate the penalty for splitting before \c Tok.
172
  unsigned splitPenalty(const AnnotatedLine &Line, const FormatToken &Tok,
173
                        bool InFunctionDecl);
174
175
  bool spaceRequiredBeforeParens(const FormatToken &Right) const;
176
177
  bool spaceRequiredBetween(const AnnotatedLine &Line, const FormatToken &Left,
178
                            const FormatToken &Right);
179
180
  bool spaceRequiredBefore(const AnnotatedLine &Line, const FormatToken &Right);
181
182
  bool mustBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
183
184
  bool canBreakBefore(const AnnotatedLine &Line, const FormatToken &Right);
185
186
  bool mustBreakForReturnType(const AnnotatedLine &Line) const;
187
188
  void printDebugInfo(const AnnotatedLine &Line);
189
190
  void calculateUnbreakableTailLengths(AnnotatedLine &Line);
191
192
  const FormatStyle &Style;
193
194
  const AdditionalKeywords &Keywords;
195
};
196
197
} // end namespace format
198
} // end namespace clang
199
200
#endif