220 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8///9/// \file10/// This file contains the definition of the Designator and Designators utility11/// 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 23void Designator::advanceToNextField() {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 51bool Designator::isFinished() {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 excess83 // 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 final140 // 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 excess152 // 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 and166 // 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 is189 // 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()) {203 case Designator::STRUCT:204 OS << '.' << I.getStructIter()->getName();205 break;206 case Designator::ARRAY:207 OS << '[' << I.getArrayIndex() << ']';208 break;209 case Designator::ARRAY_RANGE:210 OS << '[' << I.getArrayRangeStart() << "..." << I.getArrayRangeEnd()211 << ']';212 }213 }214 OS << " = ";215 return Designator;216}217 218} // namespace reorder_fields219} // namespace clang220