Checking Datatype of ParmVarDecl

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Checking Datatype of ParmVarDecl

David Chisnall via cfe-dev
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
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Checking Datatype of ParmVarDecl

David Chisnall via cfe-dev
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 <[hidden email]> 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
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Checking Datatype of ParmVarDecl

David Chisnall via cfe-dev
Awesome, thanks!

Tobi

On Wed, Jul 8, 2020 at 4:48 PM David Rector <[hidden email]> wrote:
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 <[hidden email]> 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
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

--
Regards,
Tobi Goodness Popoola
President,
National Society of Black Engineers (NSBE)
Boise State University

_______________________________________________
cfe-dev mailing list
[hidden email]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev