[cfe-dev] Checking Datatype of ParmVarDecl

David Rector via cfe-dev cfe-dev at lists.llvm.org
Wed Jul 8 15:48:14 PDT 2020


I’ll show you exactly how to do what I believe you want below, but first at the top here I want to make a point for those who design the Type interface how I think we could make it easier to use and understand:

  1. We need the GetBaseType() function I reference below to become a public Type method
  2. We probably should get rid of methods like getPointeeCXXRecordDecl(), which just add clutter and are straightforward to do with getAs<T>() and getDecl().
  3. Type::getAs<T>() should be expanded to the following to make it more flexible:

class Type {
  //…
  template<typename T,          
           bool LookThroughSemantics = false> //PROPOSED
  T *getAs() {
    // First, desugar as usual, looking for T as you go.
    // Then if you haven’t found T and LookThroughSemantics==true, 
    // you call e.g. getPointeeType(), getElementType(), etc. if  
    // the type is some kind of canonical wrapper type, then keep looking
    // through until you run out of both sugar and pointer/array/other 
    // simple wrapper types (i.e. are down to a BuiltinType or a TagType).
  }
};

	(Side note: if the previously-proposed Expr::getAs<T>() ever gets off the ground, we can make corresponding adjustments to make it more flexible as well:)

class Expr : public Stmt {
  //…
  //PROPOSED:
  template<typename T, 
	   bool LookThroughSemantics = true, 
	   bool LookThroughParens = true, 
	   bool LookThroughUnaryOps = false>
  T *getAs() {
    // peel of implicit semantics, and/or ParenExprs etc and/or unary ops or whatever,
    // depending on options, looking for T as you go.
  }
};

  4. I think we should even allow someType->getAs<CXXRecordDecl>(), which would just call dyn_cast<CXXRecordDecl>(someType->getAs<RecordType>()->getDecl()).  I.e. allow getAs<T>() to go between node categories, whenever it is straightforward and unambiguous to do so.  Could really simplify the interface if you always knew to just try getAs<T>() as a multi-purpose tool to get one thing as another, with bool template params to specify what kind of stuff you’re okay discarding in the search for T.
	
—

Now, onto solving your problem, if I understand it correctly:

If you know your VarDecl *VD has a pointer or reference type, and you just want to know if the pointee type, after removing const/volatile/etc. qualifiers, is a struct named "foo", this should do it:

bool hasPointeeRecordTypeNamedFoo(VarDecl *VD) {
  QualType PointeeType = VD->getType()->getPointeeType();
  assert(!PointeeType.isNull() && "Expected VD’s type had a pointee type");
  if (RecordType *RT = PointeeType->getAs<RecordType>()) {
    if (RT->getDecl()->getName() == "foo")
      return true;
  }
  return false;
}

If however you are not sure whether the type of VD is a pointer type, or a pointer to a pointer type, or an array, or an array of pointers etc, and really you just want to know if the base type after removing all the pointers and arrays and whatever. is "struct foo", this static method in clang/lib/AST/DeclPrinter.cpp helps:

//From clang/lib/AST/DeclPrinter.cpp:
static QualType GetBaseType(QualType T) {
  // FIXME: This should be in the Type class!
  QualType BaseType = T;
  while (!BaseType->isSpecifierType()) {
    if (const PointerType *PTy = BaseType->getAs<PointerType>())
      BaseType = PTy->getPointeeType();
    else if (const BlockPointerType *BPy = BaseType->getAs<BlockPointerType>())
      BaseType = BPy->getPointeeType();
    else if (const ArrayType* ATy = dyn_cast<ArrayType>(BaseType))
      BaseType = ATy->getElementType();
    else if (const FunctionType* FTy = BaseType->getAs<FunctionType>())
      BaseType = FTy->getReturnType();
    else if (const VectorType *VTy = BaseType->getAs<VectorType>())
      BaseType = VTy->getElementType();
    else if (const ReferenceType *RTy = BaseType->getAs<ReferenceType>())
      BaseType = RTy->getPointeeType();
    else if (const AutoType *ATy = BaseType->getAs<AutoType>())
      BaseType = ATy->getDeducedType();
    else if (const ParenType *PTy = BaseType->getAs<ParenType>())
      BaseType = PTy->desugar();
    else
      // This must be a syntax error.
      break;
  }
  return BaseType;
} 
bool hasBaseRecordTypeNamedFoo(VarDecl *VD) {
  QualType BaseType = GetBaseType(VD->getType());
  if (BaseType->getAs<RecordType>()) {
    if (RT->getDecl()->getName() == "foo")
      return true;
  }
  else
    assert(isa<BuiltinType>(BaseType.getTypePtr()) ||
           isa<EnumType>(BaseType.getTypePtr() &&
           "Fix GetBaseType, it did not unwrap this as expected…");
  return false;
}

Hope that helps, good luck,

Dave

> On Jul 8, 2020, at 3:08 PM, Tobi Popoola via cfe-dev <cfe-dev at lists.llvm.org> wrote:
> 
> Hi,
> 
> 
> Is there a way to check the struct type of a ParmVarDecl object.  Here is a snippet of what I have been trying to do so far
> 
> 
> auto ParamStructType = VarDecl->getOriginalType().getPointeeCXXRecordDec();
> 
> // trying to check if ParamStructType is some 'struct foo’
> 
> 
> Tobi 
> 
> _______________________________________________
> cfe-dev mailing list
> cfe-dev at lists.llvm.org
> https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20200708/1bddf974/attachment-0001.html>


More information about the cfe-dev mailing list