brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.1 KiB · b068ae2 Raw
196 lines · cpp
1//===----------------------------------------------------------------------===//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 provides utilities for designated initializers.11///12//===----------------------------------------------------------------------===//13 14#include "DesignatedInitializers.h"15#include "clang/AST/DeclCXX.h"16#include "clang/AST/Type.h"17#include "llvm/ADT/DenseSet.h"18#include "llvm/ADT/ScopeExit.h"19 20namespace clang::tidy::utils {21 22/// Returns true if Name is reserved, like _Foo or __Vector_base.23static inline bool isReservedName(llvm::StringRef Name) {24  // This doesn't catch all cases, but the most common.25  return Name.size() >= 2 && Name[0] == '_' &&26         (isUppercase(Name[1]) || Name[1] == '_');27}28 29namespace {30 31// Helper class to iterate over the designator names of an aggregate type.32//33// For an array type, yields [0], [1], [2]...34// For aggregate classes, yields null for each base, then .field1, .field2,35// ...36class AggregateDesignatorNames {37public:38  AggregateDesignatorNames(QualType T) {39    if (!T.isNull()) {40      T = T.getCanonicalType();41      if (T->isArrayType()) {42        IsArray = true;43        Valid = true;44        return;45      }46      if (const RecordDecl *RD = T->getAsRecordDecl()) {47        Valid = true;48        FieldsIt = RD->field_begin();49        FieldsEnd = RD->field_end();50        if (const auto *CRD = llvm::dyn_cast<CXXRecordDecl>(RD)) {51          BasesIt = CRD->bases_begin();52          BasesEnd = CRD->bases_end();53          Valid = CRD->isAggregate();54        }55        OneField = Valid && BasesIt == BasesEnd && FieldsIt != FieldsEnd &&56                   std::next(FieldsIt) == FieldsEnd;57      }58    }59  }60  // Returns false if the type was not an aggregate.61  operator bool() const { return Valid; }62  // Advance to the next element in the aggregate.63  void next() {64    if (IsArray)65      ++Index;66    else if (BasesIt != BasesEnd)67      ++BasesIt;68    else if (FieldsIt != FieldsEnd)69      ++FieldsIt;70  }71  // Print the designator to Out.72  // Returns false if we could not produce a designator for this element.73  bool append(std::string &Out, bool ForSubobject) {74    if (IsArray) {75      Out.push_back('[');76      Out.append(std::to_string(Index));77      Out.push_back(']');78      return true;79    }80    if (BasesIt != BasesEnd)81      return false; // Bases can't be designated. Should we make one up?82    if (FieldsIt != FieldsEnd) {83      llvm::StringRef FieldName;84      if (const IdentifierInfo *II = FieldsIt->getIdentifier())85        FieldName = II->getName();86 87      // For certain objects, their subobjects may be named directly.88      if (ForSubobject &&89          (FieldsIt->isAnonymousStructOrUnion() ||90           // std::array<int,3> x = {1,2,3}. Designators not strictly valid!91           (OneField && isReservedName(FieldName))))92        return true;93 94      if (!FieldName.empty() && !isReservedName(FieldName)) {95        Out.push_back('.');96        Out.append(FieldName.begin(), FieldName.end());97        return true;98      }99      return false;100    }101    return false;102  }103 104private:105  bool Valid = false;106  bool IsArray = false;107  bool OneField = false; // e.g. std::array { T __elements[N]; }108  unsigned Index = 0;109  CXXRecordDecl::base_class_const_iterator BasesIt;110  CXXRecordDecl::base_class_const_iterator BasesEnd;111  RecordDecl::field_iterator FieldsIt;112  RecordDecl::field_iterator FieldsEnd;113};114 115} // namespace116 117// Collect designator labels describing the elements of an init list.118//119// This function contributes the designators of some (sub)object, which is120// represented by the semantic InitListExpr Sem.121// This includes any nested subobjects, but *only* if they are part of the122// same original syntactic init list (due to brace elision). In other words,123// it may descend into subobjects but not written init-lists.124//125// For example: struct Outer { Inner a,b; }; struct Inner { int x, y; }126//              Outer o{{1, 2}, 3};127// This function will be called with Sem = { {1, 2}, {3, ImplicitValue} }128// It should generate designators '.a:' and '.b.x:'.129// '.a:' is produced directly without recursing into the written sublist.130// (The written sublist will have a separate collectDesignators() call later).131// Recursion with Prefix='.b' and Sem = {3, ImplicitValue} produces '.b.x:'.132static void collectDesignators(133    const InitListExpr *Sem, llvm::DenseMap<SourceLocation, std::string> &Out,134    const llvm::DenseSet<SourceLocation> &NestedBraces, std::string &Prefix) {135  if (!Sem || Sem->isTransparent())136    return;137  assert(Sem->isSemanticForm());138 139  // The elements of the semantic form all correspond to direct subobjects of140  // the aggregate type. `Fields` iterates over these subobject names.141  AggregateDesignatorNames Fields(Sem->getType());142  if (!Fields)143    return;144  for (const Expr *Init : Sem->inits()) {145    auto Next = llvm::make_scope_exit([&, Size(Prefix.size())] {146      Fields.next();       // Always advance to the next subobject name.147      Prefix.resize(Size); // Erase any designator we appended.148    });149    // Skip for a broken initializer or if it is a "hole" in a subobject that150    // was not explicitly initialized.151    if (!Init || llvm::isa<ImplicitValueInitExpr>(Init))152      continue;153 154    const auto *BraceElidedSubobject = llvm::dyn_cast<InitListExpr>(Init);155    if (BraceElidedSubobject &&156        NestedBraces.contains(BraceElidedSubobject->getLBraceLoc()))157      BraceElidedSubobject = nullptr; // there were braces!158 159    if (!Fields.append(Prefix, BraceElidedSubobject != nullptr))160      continue; // no designator available for this subobject161    if (BraceElidedSubobject) {162      // If the braces were elided, this aggregate subobject is initialized163      // inline in the same syntactic list.164      // Descend into the semantic list describing the subobject.165      // (NestedBraces are still correct, they're from the same syntactic166      // list).167      collectDesignators(BraceElidedSubobject, Out, NestedBraces, Prefix);168      continue;169    }170    Out.try_emplace(Init->getBeginLoc(), Prefix);171  }172}173 174llvm::DenseMap<SourceLocation, std::string>175getUnwrittenDesignators(const InitListExpr *Syn) {176  assert(Syn->isSyntacticForm());177 178  // collectDesignators needs to know which InitListExprs in the semantic tree179  // were actually written, but InitListExpr::isExplicit() lies.180  // Instead, record where braces of sub-init-lists occur in the syntactic form.181  llvm::DenseSet<SourceLocation> NestedBraces;182  for (const Expr *Init : Syn->inits())183    if (auto *Nested = llvm::dyn_cast<InitListExpr>(Init))184      NestedBraces.insert(Nested->getLBraceLoc());185 186  // Traverse the semantic form to find the designators.187  // We use their SourceLocation to correlate with the syntactic form later.188  llvm::DenseMap<SourceLocation, std::string> Designators;189  std::string EmptyPrefix;190  collectDesignators(Syn->isSemanticForm() ? Syn : Syn->getSemanticForm(),191                     Designators, NestedBraces, EmptyPrefix);192  return Designators;193}194 195} // namespace clang::tidy::utils196