clang-tools 22.0.0git
Designator.cpp
Go to the documentation of this file.
1//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- 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 contains the definition of the Designator and Designators utility
11/// classes.
12///
13//===----------------------------------------------------------------------===//
14
15#include "Designator.h"
16#include "clang/AST/ASTContext.h"
17#include "clang/AST/Expr.h"
18#include "llvm/Support/raw_ostream.h"
19
20namespace clang {
21namespace reorder_fields {
22
24 assert(!isFinished() && "Iterator is already finished");
25 switch (Tag) {
26 case STRUCT:
27 if (StructIt.Record->isUnion()) {
28 // Union always finishes on first increment.
29 StructIt.Field = StructIt.Record->field_end();
30 Type = QualType();
31 break;
32 }
33 ++StructIt.Field;
34 if (StructIt.Field != StructIt.Record->field_end()) {
35 Type = StructIt.Field->getType();
36 } else {
37 Type = QualType();
38 }
39 break;
40 case ARRAY:
41 ++ArrayIt.Index;
42 break;
43 case ARRAY_RANGE:
44 ArrayIt.Index = ArrayRangeIt.End + 1;
45 ArrayIt.Size = ArrayRangeIt.Size;
46 Tag = ARRAY;
47 break;
48 }
49}
50
52 switch (Tag) {
53 case STRUCT:
54 return StructIt.Field == StructIt.Record->field_end();
55 case ARRAY:
56 return ArrayIt.Index == ArrayIt.Size;
57 case ARRAY_RANGE:
58 return ArrayRangeIt.End == ArrayRangeIt.Size;
59 }
60 return false;
61}
62
63Designators::Designators(const Expr *Init, const InitListExpr *ILE,
64 const ASTContext *Context)
65 : Context(Context) {
66 if (ILE->getType()->isArrayType()) {
67 const ConstantArrayType *CAT =
68 Context->getAsConstantArrayType(ILE->getType());
69 // Only constant size arrays are supported.
70 if (!CAT) {
71 DesignatorList.clear();
72 return;
73 }
74 DesignatorList.push_back(
75 {CAT->getElementType(), 0, CAT->getSize().getZExtValue()});
76 } else {
77 const RecordDecl *DesignatorRD = ILE->getType()->getAsRecordDecl();
78 DesignatorList.push_back({DesignatorRD->field_begin()->getType(),
79 DesignatorRD->field_begin(), DesignatorRD});
80 }
81
82 // If the designator list is empty at this point, then there must be excess
83 // elements in the initializer list. They are not currently supported.
84 if (DesignatorList.empty())
85 return;
86
87 if (!enterImplicitInitLists(Init))
88 DesignatorList.clear();
89}
90
91Designators::Designators(const DesignatedInitExpr *DIE, const InitListExpr *ILE,
92 const ASTContext *Context)
93 : Context(Context) {
94 for (const auto &D : DIE->designators()) {
95 if (D.isFieldDesignator()) {
96 RecordDecl *DesignatorRecord = D.getFieldDecl()->getParent();
97 for (auto FieldIt = DesignatorRecord->field_begin();
98 FieldIt != DesignatorRecord->field_end(); ++FieldIt) {
99 if (*FieldIt == D.getFieldDecl()) {
100 DesignatorList.push_back(
101 {FieldIt->getType(), FieldIt, DesignatorRecord});
102 break;
103 }
104 }
105 } else {
106 const QualType CurrentType = DesignatorList.empty()
107 ? ILE->getType()
108 : DesignatorList.back().getType();
109 const ConstantArrayType *CAT =
110 Context->getAsConstantArrayType(CurrentType);
111 if (!CAT) {
112 // Non-constant-sized arrays are not supported.
113 DesignatorList.clear();
114 return;
115 }
116 if (D.isArrayDesignator()) {
117 DesignatorList.push_back({CAT->getElementType(),
118 DIE->getArrayIndex(D)
119 ->EvaluateKnownConstInt(*Context)
120 .getZExtValue(),
121 CAT->getSize().getZExtValue()});
122 } else if (D.isArrayRangeDesignator()) {
123 DesignatorList.push_back({CAT->getElementType(),
124 DIE->getArrayRangeStart(D)
125 ->EvaluateKnownConstInt(*Context)
126 .getZExtValue(),
127 DIE->getArrayRangeEnd(D)
128 ->EvaluateKnownConstInt(*Context)
129 .getZExtValue(),
130 CAT->getSize().getZExtValue()});
131 } else {
132 llvm_unreachable("Unexpected designator kind");
133 }
134 }
135 }
136}
137
138bool Designators::advanceToNextField(const Expr *Init) {
139 // Remove all designators that refer to the last field of a struct or final
140 // element of the array.
141 while (!DesignatorList.empty()) {
142 auto &CurrentDesignator = DesignatorList.back();
143 CurrentDesignator.advanceToNextField();
144 if (CurrentDesignator.isFinished()) {
145 DesignatorList.pop_back();
146 continue;
147 }
148 break;
149 }
150
151 // If the designator list is empty at this point, then there must be excess
152 // elements in the initializer list. They are not currently supported.
153 if (DesignatorList.empty())
154 return false;
155
156 if (!enterImplicitInitLists(Init)) {
157 DesignatorList.clear();
158 return false;
159 }
160
161 return true;
162}
163
164bool Designators::enterImplicitInitLists(const Expr *Init) {
165 // Check for missing braces by comparing the type of the last designator and
166 // type of Init.
167 while (true) {
168 const QualType T = DesignatorList.back().getType();
169 // If the types match, there are no missing braces.
170 if (Init->getType() == T)
171 break;
172
173 // If the current type is a struct, then get its first field.
174 if (T->isRecordType()) {
175 DesignatorList.push_back({T->getAsRecordDecl()->field_begin()->getType(),
176 T->getAsRecordDecl()->field_begin(),
177 T->getAsRecordDecl()});
178 continue;
179 }
180 // If the current type is an array, then get its first element.
181 if (T->isArrayType()) {
182 DesignatorList.push_back(
183 {Context->getAsArrayType(T)->getElementType(), 0,
184 Context->getAsConstantArrayType(T)->getSize().getZExtValue()});
185 continue;
186 }
187
188 // The initializer doesn't match the expected type. The initializer list is
189 // invalid.
190 return false;
191 }
192
193 return true;
194}
195
196std::string Designators::toString() const {
197 if (DesignatorList.empty())
198 return "";
199 std::string Designator;
200 llvm::raw_string_ostream OS(Designator);
201 for (auto &I : DesignatorList) {
202 switch (I.getTag()) {
204 OS << '.' << I.getStructIter()->getName();
205 break;
207 OS << '[' << I.getArrayIndex() << ']';
208 break;
210 OS << '[' << I.getArrayRangeStart() << "..." << I.getArrayRangeEnd()
211 << ']';
212 }
213 }
214 OS << " = ";
215 return Designator;
216}
217
218} // namespace reorder_fields
219} // namespace clang
This file contains the declarations of the Designator and Designators utility classes.
Represents a part of a designation in a C99/C++20 designated initializer.
Definition Designator.h:29
bool isFinished()
Checks if the iterator has iterated through all elements.
void advanceToNextField()
Moves the iterator to the next element.
std::string toString() const
Gets a string representation from a list of designators.
bool advanceToNextField(const Expr *Init)
Moves the designators to the next initializer in the struct/array.
Designators(const Expr *Init, const InitListExpr *ILE, const ASTContext *Context)
Initialize to the first member of the struct/array.
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//