aboutsummaryrefslogtreecommitdiff
path: root/clang-tools-extra/clang-reorder-fields/Designator.h
blob: 859be28e66de730aacd4ad52c36ffac39e4f0b01 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
//===-- tools/extra/clang-reorder-fields/utils/Designator.h -----*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file contains the declarations of the Designator and Designators
/// utility classes.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H

#include "clang/AST/Decl.h"
#include "clang/AST/Expr.h"
#include "clang/AST/Type.h"

namespace clang {
namespace reorder_fields {

/// Represents a part of a designation in a C99/C++20 designated initializer. It
/// is a tagged union of different kinds of designators: struct, array and array
/// range. Holds enough information to be able to advance to the next field and
/// to know when all fields have been iterated through.
class Designator {
public:
  enum Kind { STRUCT, ARRAY, ARRAY_RANGE };

  Designator(const QualType Type, RecordDecl::field_iterator Field,
             const RecordDecl *RD)
      : Tag(STRUCT), Type(Type), StructIt({Field, RD}) {}

  Designator(const QualType Type, uint64_t Idx, uint64_t Size)
      : Tag(ARRAY), Type(Type), ArrayIt({Idx, Size}) {}

  Designator(const QualType Type, uint64_t Start, uint64_t End, uint64_t Size)
      : Tag(ARRAY_RANGE), Type(Type), ArrayRangeIt({Start, End, Size}) {}

  /// Moves the iterator to the next element.
  void advanceToNextField();

  /// Checks if the iterator has iterated through all elements.
  bool isFinished();

  Kind getTag() const { return Tag; }
  QualType getType() const { return Type; }

  const RecordDecl::field_iterator getStructIter() const {
    assert(Tag == STRUCT && "Must be a field designator");
    return StructIt.Field;
  }

  const RecordDecl *getStructDecl() const {
    assert(Tag == STRUCT && "Must be a field designator");
    return StructIt.Record;
  }

  uint64_t getArrayIndex() const {
    assert(Tag == ARRAY && "Must be an array designator");
    return ArrayIt.Index;
  }

  uint64_t getArrayRangeStart() const {
    assert(Tag == ARRAY_RANGE && "Must be an array range designator");
    return ArrayRangeIt.Start;
  }

  uint64_t getArrayRangeEnd() const {
    assert(Tag == ARRAY_RANGE && "Must be an array range designator");
    return ArrayRangeIt.End;
  }

  uint64_t getArraySize() const {
    assert((Tag == ARRAY || Tag == ARRAY_RANGE) &&
           "Must be an array or range designator");
    if (Tag == ARRAY)
      return ArrayIt.Size;
    return ArrayRangeIt.Size;
  }

private:
  /// Type of the designator.
  Kind Tag;

  /// Type of the designated entry. For arrays this is the type of the element.
  QualType Type;

  /// Field designator has the iterator to the field and the record the field
  /// is declared in.
  struct StructIter {
    RecordDecl::field_iterator Field;
    const RecordDecl *Record;
  };

  /// Array designator has an index and size of the array.
  struct ArrayIter {
    uint64_t Index;
    uint64_t Size;
  };

  /// Array range designator has a start and end index and size of the array.
  struct ArrayRangeIter {
    uint64_t Start;
    uint64_t End;
    uint64_t Size;
  };

  union {
    StructIter StructIt;
    ArrayIter ArrayIt;
    ArrayRangeIter ArrayRangeIt;
  };
};

/// List of designators.
class Designators {
public:
  /// Initialize to the first member of the struct/array. Enters implicit
  /// initializer lists until a type that matches Init is found.
  Designators(const Expr *Init, const InitListExpr *ILE,
              const ASTContext *Context);

  /// Initialize to the designators of the given expression.
  Designators(const DesignatedInitExpr *DIE, const InitListExpr *ILE,
              const ASTContext *Context);

  /// Return whether this designator list is valid.
  bool isValid() const { return !DesignatorList.empty(); }

  /// Moves the designators to the next initializer in the struct/array. If the
  /// type of next initializer doesn't match the expected type then there are
  /// omitted braces and we add new designators to reflect that.
  bool advanceToNextField(const Expr *Init);

  /// Gets a string representation from a list of designators. This string will
  /// be inserted before an initializer expression to make it designated.
  std::string toString() const;

  size_t size() const { return DesignatorList.size(); }

  SmallVector<Designator>::const_iterator begin() const {
    return DesignatorList.begin();
  }
  SmallVector<Designator>::const_iterator end() const {
    return DesignatorList.end();
  }

private:
  /// Enters any implicit initializer lists until a type that matches the given
  /// expression is found.
  bool enterImplicitInitLists(const Expr *Init);

  const ASTContext *Context;
  SmallVector<Designator, 1> DesignatorList;
};

} // namespace reorder_fields
} // namespace clang

#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_REORDER_FIELDS_UTILS_DESIGNATOR_H