//===-- tools/extra/clang-reorder-fields/utils/Designator.cpp ---*- 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 definition of the Designator and Designators utility /// classes. /// //===----------------------------------------------------------------------===// #include "Designator.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Expr.h" #include "llvm/Support/raw_ostream.h" namespace clang { namespace reorder_fields { void Designator::advanceToNextField() { assert(!isFinished() && "Iterator is already finished"); switch (Tag) { case STRUCT: if (StructIt.Record->isUnion()) { // Union always finishes on first increment. StructIt.Field = StructIt.Record->field_end(); Type = QualType(); break; } ++StructIt.Field; if (StructIt.Field != StructIt.Record->field_end()) { Type = StructIt.Field->getType(); } else { Type = QualType(); } break; case ARRAY: ++ArrayIt.Index; break; case ARRAY_RANGE: ArrayIt.Index = ArrayRangeIt.End + 1; ArrayIt.Size = ArrayRangeIt.Size; Tag = ARRAY; break; } } bool Designator::isFinished() { switch (Tag) { case STRUCT: return StructIt.Field == StructIt.Record->field_end(); case ARRAY: return ArrayIt.Index == ArrayIt.Size; case ARRAY_RANGE: return ArrayRangeIt.End == ArrayRangeIt.Size; } return false; } Designators::Designators(const Expr *Init, const InitListExpr *ILE, const ASTContext *Context) : Context(Context) { if (ILE->getType()->isArrayType()) { const ConstantArrayType *CAT = Context->getAsConstantArrayType(ILE->getType()); // Only constant size arrays are supported. if (!CAT) { DesignatorList.clear(); return; } DesignatorList.push_back( {CAT->getElementType(), 0, CAT->getSize().getZExtValue()}); } else { const RecordDecl *DesignatorRD = ILE->getType()->getAsRecordDecl(); DesignatorList.push_back({DesignatorRD->field_begin()->getType(), DesignatorRD->field_begin(), DesignatorRD}); } // If the designator list is empty at this point, then there must be excess // elements in the initializer list. They are not currently supported. if (DesignatorList.empty()) return; if (!enterImplicitInitLists(Init)) DesignatorList.clear(); } Designators::Designators(const DesignatedInitExpr *DIE, const InitListExpr *ILE, const ASTContext *Context) : Context(Context) { for (const auto &D : DIE->designators()) { if (D.isFieldDesignator()) { RecordDecl *DesignatorRecord = D.getFieldDecl()->getParent(); for (auto FieldIt = DesignatorRecord->field_begin(); FieldIt != DesignatorRecord->field_end(); ++FieldIt) { if (*FieldIt == D.getFieldDecl()) { DesignatorList.push_back( {FieldIt->getType(), FieldIt, DesignatorRecord}); break; } } } else { const QualType CurrentType = DesignatorList.empty() ? ILE->getType() : DesignatorList.back().getType(); const ConstantArrayType *CAT = Context->getAsConstantArrayType(CurrentType); if (!CAT) { // Non-constant-sized arrays are not supported. DesignatorList.clear(); return; } if (D.isArrayDesignator()) { DesignatorList.push_back({CAT->getElementType(), DIE->getArrayIndex(D) ->EvaluateKnownConstInt(*Context) .getZExtValue(), CAT->getSize().getZExtValue()}); } else if (D.isArrayRangeDesignator()) { DesignatorList.push_back({CAT->getElementType(), DIE->getArrayRangeStart(D) ->EvaluateKnownConstInt(*Context) .getZExtValue(), DIE->getArrayRangeEnd(D) ->EvaluateKnownConstInt(*Context) .getZExtValue(), CAT->getSize().getZExtValue()}); } else { llvm_unreachable("Unexpected designator kind"); } } } } bool Designators::advanceToNextField(const Expr *Init) { // Remove all designators that refer to the last field of a struct or final // element of the array. while (!DesignatorList.empty()) { auto &CurrentDesignator = DesignatorList.back(); CurrentDesignator.advanceToNextField(); if (CurrentDesignator.isFinished()) { DesignatorList.pop_back(); continue; } break; } // If the designator list is empty at this point, then there must be excess // elements in the initializer list. They are not currently supported. if (DesignatorList.empty()) return false; if (!enterImplicitInitLists(Init)) { DesignatorList.clear(); return false; } return true; } bool Designators::enterImplicitInitLists(const Expr *Init) { // Check for missing braces by comparing the type of the last designator and // type of Init. while (true) { const QualType T = DesignatorList.back().getType(); // If the types match, there are no missing braces. if (Init->getType() == T) break; // If the current type is a struct, then get its first field. if (T->isRecordType()) { DesignatorList.push_back({T->getAsRecordDecl()->field_begin()->getType(), T->getAsRecordDecl()->field_begin(), T->getAsRecordDecl()}); continue; } // If the current type is an array, then get its first element. if (T->isArrayType()) { DesignatorList.push_back( {Context->getAsArrayType(T)->getElementType(), 0, Context->getAsConstantArrayType(T)->getSize().getZExtValue()}); continue; } // The initializer doesn't match the expected type. The initializer list is // invalid. return false; } return true; } std::string Designators::toString() const { if (DesignatorList.empty()) return ""; std::string Designator; llvm::raw_string_ostream OS(Designator); for (auto &I : DesignatorList) { switch (I.getTag()) { case Designator::STRUCT: OS << '.' << I.getStructIter()->getName(); break; case Designator::ARRAY: OS << '[' << I.getArrayIndex() << ']'; break; case Designator::ARRAY_RANGE: OS << '[' << I.getArrayRangeStart() << "..." << I.getArrayRangeEnd() << ']'; } } OS << " = "; return Designator; } } // namespace reorder_fields } // namespace clang