//===- TypeLoc.cpp - Type Source Info Wrapper -----------------------------===// // // 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 // //===----------------------------------------------------------------------===// // // This file defines the TypeLoc subclasses implementations. // //===----------------------------------------------------------------------===// #include "clang/AST/TypeLoc.h" #include "clang/AST/DeclTemplate.h" #include "clang/AST/ASTContext.h" #include "clang/AST/Attr.h" #include "clang/AST/Expr.h" #include "clang/AST/NestedNameSpecifier.h" #include "clang/AST/TemplateBase.h" #include "clang/AST/TemplateName.h" #include "clang/AST/TypeLocVisitor.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/Specifiers.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/MathExtras.h" #include #include #include #include using namespace clang; static const unsigned TypeLocMaxDataAlign = alignof(void *); //===----------------------------------------------------------------------===// // TypeLoc Implementation //===----------------------------------------------------------------------===// namespace { class TypeLocRanger : public TypeLocVisitor { public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ SourceRange Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ return TyLoc.getLocalSourceRange(); \ } #include "clang/AST/TypeLocNodes.def" }; } // namespace SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { if (TL.isNull()) return SourceRange(); return TypeLocRanger().Visit(TL); } namespace { class TypeAligner : public TypeLocVisitor { public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ return TyLoc.getLocalDataAlignment(); \ } #include "clang/AST/TypeLocNodes.def" }; } // namespace /// Returns the alignment of the type source info data block. unsigned TypeLoc::getLocalAlignmentForType(QualType Ty) { if (Ty.isNull()) return 1; return TypeAligner().Visit(TypeLoc(Ty, nullptr)); } namespace { class TypeSizer : public TypeLocVisitor { public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ unsigned Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ return TyLoc.getLocalDataSize(); \ } #include "clang/AST/TypeLocNodes.def" }; } // namespace /// Returns the size of the type source info data block. unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { unsigned Total = 0; TypeLoc TyLoc(Ty, nullptr); unsigned MaxAlign = 1; while (!TyLoc.isNull()) { unsigned Align = getLocalAlignmentForType(TyLoc.getType()); MaxAlign = std::max(Align, MaxAlign); Total = llvm::alignTo(Total, Align); Total += TypeSizer().Visit(TyLoc); TyLoc = TyLoc.getNextTypeLoc(); } Total = llvm::alignTo(Total, MaxAlign); return Total; } namespace { class NextLoc : public TypeLocVisitor { public: #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ TypeLoc Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ return TyLoc.getNextTypeLoc(); \ } #include "clang/AST/TypeLocNodes.def" }; } // namespace /// Get the next TypeLoc pointed by this TypeLoc, e.g for "int*" the /// TypeLoc is a PointerLoc and next TypeLoc is for "int". TypeLoc TypeLoc::getNextTypeLocImpl(TypeLoc TL) { return NextLoc().Visit(TL); } /// Initializes a type location, and all of its children /// recursively, as if the entire tree had been written in the /// given location. void TypeLoc::initializeImpl(ASTContext &Context, TypeLoc TL, SourceLocation Loc) { while (true) { switch (TL.getTypeLocClass()) { #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ case CLASS: { \ CLASS##TypeLoc TLCasted = TL.castAs(); \ TLCasted.initializeLocal(Context, Loc); \ TL = TLCasted.getNextTypeLoc(); \ if (!TL) return; \ continue; \ } #include "clang/AST/TypeLocNodes.def" } } } namespace { class TypeLocCopier : public TypeLocVisitor { TypeLoc Source; public: TypeLocCopier(TypeLoc source) : Source(source) {} #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ void Visit##CLASS##TypeLoc(CLASS##TypeLoc dest) { \ dest.copyLocal(Source.castAs()); \ } #include "clang/AST/TypeLocNodes.def" }; } // namespace void TypeLoc::copy(TypeLoc other) { assert(getFullDataSize() == other.getFullDataSize()); // If both data pointers are aligned to the maximum alignment, we // can memcpy because getFullDataSize() accurately reflects the // layout of the data. if (reinterpret_cast(Data) == llvm::alignTo(reinterpret_cast(Data), TypeLocMaxDataAlign) && reinterpret_cast(other.Data) == llvm::alignTo(reinterpret_cast(other.Data), TypeLocMaxDataAlign)) { memcpy(Data, other.Data, getFullDataSize()); return; } // Copy each of the pieces. TypeLoc TL(getType(), Data); do { TypeLocCopier(other).Visit(TL); other = other.getNextTypeLoc(); } while ((TL = TL.getNextTypeLoc())); } SourceLocation TypeLoc::getBeginLoc() const { TypeLoc Cur = *this; TypeLoc LeftMost = Cur; while (true) { switch (Cur.getTypeLocClass()) { case Elaborated: LeftMost = Cur; break; case FunctionProto: if (Cur.castAs().getTypePtr() ->hasTrailingReturn()) { LeftMost = Cur; break; } LLVM_FALLTHROUGH; case FunctionNoProto: case ConstantArray: case DependentSizedArray: case IncompleteArray: case VariableArray: // FIXME: Currently QualifiedTypeLoc does not have a source range case Qualified: Cur = Cur.getNextTypeLoc(); continue; default: if (Cur.getLocalSourceRange().getBegin().isValid()) LeftMost = Cur; Cur = Cur.getNextTypeLoc(); if (Cur.isNull()) break; continue; } // switch break; } // while return LeftMost.getLocalSourceRange().getBegin(); } SourceLocation TypeLoc::getEndLoc() const { TypeLoc Cur = *this; TypeLoc Last; while (true) { switch (Cur.getTypeLocClass()) { default: if (!Last) Last = Cur; return Last.getLocalSourceRange().getEnd(); case Paren: case ConstantArray: case DependentSizedArray: case IncompleteArray: case VariableArray: case FunctionNoProto: Last = Cur; break; case FunctionProto: if (Cur.castAs().getTypePtr()->hasTrailingReturn()) Last = TypeLoc(); else Last = Cur; break; case Pointer: case BlockPointer: case MemberPointer: case LValueReference: case RValueReference: case PackExpansion: if (!Last) Last = Cur; break; case Qualified: case Elaborated: break; } Cur = Cur.getNextTypeLoc(); } } namespace { struct TSTChecker : public TypeLocVisitor { // Overload resolution does the real work for us. static bool isTypeSpec(TypeSpecTypeLoc _) { return true; } static bool isTypeSpec(TypeLoc _) { return false; } #define ABSTRACT_TYPELOC(CLASS, PARENT) #define TYPELOC(CLASS, PARENT) \ bool Visit##CLASS##TypeLoc(CLASS##TypeLoc TyLoc) { \ return isTypeSpec(TyLoc); \ } #include "clang/AST/TypeLocNodes.def" }; } // namespace /// Determines if the given type loc corresponds to a /// TypeSpecTypeLoc. Since there is not actually a TypeSpecType in /// the type hierarchy, this is made somewhat complicated. /// /// There are a lot of types that currently use TypeSpecTypeLoc /// because it's a convenient base class. Ideally we would not accept /// those here, but ideally we would have better implementations for /// them. bool TypeSpecTypeLoc::isKind(const TypeLoc &TL) { if (TL.getType().hasLocalQualifiers()) return false; return TSTChecker().Visit(TL); } bool TagTypeLoc::isDefinition() const { TagDecl *D = getDecl(); return D->isCompleteDefinition() && (D->getIdentifier() == nullptr || D->getLocation() == getNameLoc()); } // Reimplemented to account for GNU/C++ extension // typeof unary-expression // where there are no parentheses. SourceRange TypeOfExprTypeLoc::getLocalSourceRange() const { if (getRParenLoc().isValid()) return SourceRange(getTypeofLoc(), getRParenLoc()); else return SourceRange(getTypeofLoc(), getUnderlyingExpr()->getSourceRange().getEnd()); } TypeSpecifierType BuiltinTypeLoc::getWrittenTypeSpec() const { if (needsExtraLocalData()) return static_cast(getWrittenBuiltinSpecs().Type); switch (getTypePtr()->getKind()) { case BuiltinType::Void: return TST_void; case BuiltinType::Bool: return TST_bool; case BuiltinType::Char_U: case BuiltinType::Char_S: return TST_char; case BuiltinType::Char8: return TST_char8; case BuiltinType::Char16: return TST_char16; case BuiltinType::Char32: return TST_char32; case BuiltinType::WChar_S: case BuiltinType::WChar_U: return TST_wchar; case BuiltinType::UChar: case BuiltinType::UShort: case BuiltinType::UInt: case BuiltinType::ULong: case BuiltinType::ULongLong: case BuiltinType::UInt128: case BuiltinType::SChar: case BuiltinType::Short: case BuiltinType::Int: case BuiltinType::Long: case BuiltinType::LongLong: case BuiltinType::Int128: case BuiltinType::Half: case BuiltinType::Float: case BuiltinType::Double: case BuiltinType::LongDouble: case BuiltinType::Float16: case BuiltinType::Float128: case BuiltinType::ShortAccum: case BuiltinType::Accum: case BuiltinType::LongAccum: case BuiltinType::UShortAccum: case BuiltinType::UAccum: case BuiltinType::ULongAccum: case BuiltinType::ShortFract: case BuiltinType::Fract: case BuiltinType::LongFract: case BuiltinType::UShortFract: case BuiltinType::UFract: case BuiltinType::ULongFract: case BuiltinType::SatShortAccum: case BuiltinType::SatAccum: case BuiltinType::SatLongAccum: case BuiltinType::SatUShortAccum: case BuiltinType::SatUAccum: case BuiltinType::SatULongAccum: case BuiltinType::SatShortFract: case BuiltinType::SatFract: case BuiltinType::SatLongFract: case BuiltinType::SatUShortFract: case BuiltinType::SatUFract: case BuiltinType::SatULongFract: llvm_unreachable("Builtin type needs extra local data!"); // Fall through, if the impossible happens. case BuiltinType::NullPtr: case BuiltinType::Overload: case BuiltinType::Dependent: case BuiltinType::BoundMember: case BuiltinType::UnknownAny: case BuiltinType::ARCUnbridgedCast: case BuiltinType::PseudoObject: case BuiltinType::ObjCId: case BuiltinType::ObjCClass: case BuiltinType::ObjCSel: #define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \ case BuiltinType::Id: #include "clang/Basic/OpenCLImageTypes.def" #define EXT_OPAQUE_TYPE(ExtType, Id, Ext) \ case BuiltinType::Id: #include "clang/Basic/OpenCLExtensionTypes.def" case BuiltinType::OCLSampler: case BuiltinType::OCLEvent: case BuiltinType::OCLClkEvent: case BuiltinType::OCLQueue: case BuiltinType::OCLReserveID: #define SVE_TYPE(Name, Id, SingletonId) \ case BuiltinType::Id: #include "clang/Basic/AArch64SVEACLETypes.def" case BuiltinType::BuiltinFn: case BuiltinType::OMPArraySection: return TST_unspecified; } llvm_unreachable("Invalid BuiltinType Kind!"); } TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { while (ParenTypeLoc PTL = TL.getAs()) TL = PTL.getInnerLoc(); return TL; } SourceLocation TypeLoc::findNullabilityLoc() const { if (auto ATL = getAs()) { const Attr *A = ATL.getAttr(); if (A && (isa(A) || isa(A) || isa(A))) return A->getLocation(); } return {}; } TypeLoc TypeLoc::findExplicitQualifierLoc() const { // Qualified types. if (auto qual = getAs()) return qual; TypeLoc loc = IgnoreParens(); // Attributed types. if (auto attr = loc.getAs()) { if (attr.isQualifier()) return attr; return attr.getModifiedLoc().findExplicitQualifierLoc(); } // C11 _Atomic types. if (auto atomic = loc.getAs()) { return atomic; } return {}; } void ObjCTypeParamTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setNameLoc(Loc); if (!getNumProtocols()) return; setProtocolLAngleLoc(Loc); setProtocolRAngleLoc(Loc); for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) setProtocolLoc(i, Loc); } void ObjCObjectTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setHasBaseTypeAsWritten(true); setTypeArgsLAngleLoc(Loc); setTypeArgsRAngleLoc(Loc); for (unsigned i = 0, e = getNumTypeArgs(); i != e; ++i) { setTypeArgTInfo(i, Context.getTrivialTypeSourceInfo( getTypePtr()->getTypeArgsAsWritten()[i], Loc)); } setProtocolLAngleLoc(Loc); setProtocolRAngleLoc(Loc); for (unsigned i = 0, e = getNumProtocols(); i != e; ++i) setProtocolLoc(i, Loc); } SourceRange AttributedTypeLoc::getLocalSourceRange() const { // Note that this does *not* include the range of the attribute // enclosure, e.g.: // __attribute__((foo(bar))) // ^~~~~~~~~~~~~~~ ~~ // or // [[foo(bar)]] // ^~ ~~ // That enclosure doesn't necessarily belong to a single attribute // anyway. return getAttr() ? getAttr()->getRange() : SourceRange(); } void TypeOfTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { TypeofLikeTypeLoc ::initializeLocal(Context, Loc); this->getLocalData()->UnderlyingTInfo = Context.getTrivialTypeSourceInfo( getUnderlyingType(), Loc); } void UnaryTransformTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setKWLoc(Loc); setRParenLoc(Loc); setLParenLoc(Loc); this->setUnderlyingTInfo( Context.getTrivialTypeSourceInfo(getTypePtr()->getBaseType(), Loc)); } void ElaboratedTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setElaboratedKeywordLoc(Loc); NestedNameSpecifierLocBuilder Builder; Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); setQualifierLoc(Builder.getWithLocInContext(Context)); } void DependentNameTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setElaboratedKeywordLoc(Loc); NestedNameSpecifierLocBuilder Builder; Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); setQualifierLoc(Builder.getWithLocInContext(Context)); setNameLoc(Loc); } void DependentTemplateSpecializationTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setElaboratedKeywordLoc(Loc); if (getTypePtr()->getQualifier()) { NestedNameSpecifierLocBuilder Builder; Builder.MakeTrivial(Context, getTypePtr()->getQualifier(), Loc); setQualifierLoc(Builder.getWithLocInContext(Context)); } else { setQualifierLoc(NestedNameSpecifierLoc()); } setTemplateKeywordLoc(Loc); setTemplateNameLoc(Loc); setLAngleLoc(Loc); setRAngleLoc(Loc); TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), getArgInfos(), Loc); } void TemplateSpecializationTypeLoc::initializeArgLocs(ASTContext &Context, unsigned NumArgs, const TemplateArgument *Args, TemplateArgumentLocInfo *ArgInfos, SourceLocation Loc) { for (unsigned i = 0, e = NumArgs; i != e; ++i) { switch (Args[i].getKind()) { case TemplateArgument::Null: llvm_unreachable("Impossible TemplateArgument"); case TemplateArgument::Integral: case TemplateArgument::Declaration: case TemplateArgument::NullPtr: ArgInfos[i] = TemplateArgumentLocInfo(); break; case TemplateArgument::Expression: ArgInfos[i] = TemplateArgumentLocInfo(Args[i].getAsExpr()); break; case TemplateArgument::Type: ArgInfos[i] = TemplateArgumentLocInfo( Context.getTrivialTypeSourceInfo(Args[i].getAsType(), Loc)); break; case TemplateArgument::Template: case TemplateArgument::TemplateExpansion: { NestedNameSpecifierLocBuilder Builder; TemplateName Template = Args[i].getAsTemplateOrTemplatePattern(); if (DependentTemplateName *DTN = Template.getAsDependentTemplateName()) Builder.MakeTrivial(Context, DTN->getQualifier(), Loc); else if (QualifiedTemplateName *QTN = Template.getAsQualifiedTemplateName()) Builder.MakeTrivial(Context, QTN->getQualifier(), Loc); ArgInfos[i] = TemplateArgumentLocInfo( Builder.getWithLocInContext(Context), Loc, Args[i].getKind() == TemplateArgument::Template ? SourceLocation() : Loc); break; } case TemplateArgument::Pack: ArgInfos[i] = TemplateArgumentLocInfo(); break; } } } DeclarationNameInfo AutoTypeLoc::getConceptNameInfo() const { return DeclarationNameInfo(getNamedConcept()->getDeclName(), getLocalData()->ConceptNameLoc); } void AutoTypeLoc::initializeLocal(ASTContext &Context, SourceLocation Loc) { setNestedNameSpecifierLoc(NestedNameSpecifierLoc()); setTemplateKWLoc(Loc); setConceptNameLoc(Loc); setFoundDecl(nullptr); setRAngleLoc(Loc); setLAngleLoc(Loc); TemplateSpecializationTypeLoc::initializeArgLocs(Context, getNumArgs(), getTypePtr()->getArgs(), getArgInfos(), Loc); setNameLoc(Loc); } namespace { class GetContainedAutoTypeLocVisitor : public TypeLocVisitor { public: using TypeLocVisitor::Visit; TypeLoc VisitAutoTypeLoc(AutoTypeLoc TL) { return TL; } // Only these types can contain the desired 'auto' type. TypeLoc VisitElaboratedTypeLoc(ElaboratedTypeLoc T) { return Visit(T.getNamedTypeLoc()); } TypeLoc VisitQualifiedTypeLoc(QualifiedTypeLoc T) { return Visit(T.getUnqualifiedLoc()); } TypeLoc VisitPointerTypeLoc(PointerTypeLoc T) { return Visit(T.getPointeeLoc()); } TypeLoc VisitBlockPointerTypeLoc(BlockPointerTypeLoc T) { return Visit(T.getPointeeLoc()); } TypeLoc VisitReferenceTypeLoc(ReferenceTypeLoc T) { return Visit(T.getPointeeLoc()); } TypeLoc VisitMemberPointerTypeLoc(MemberPointerTypeLoc T) { return Visit(T.getPointeeLoc()); } TypeLoc VisitArrayTypeLoc(ArrayTypeLoc T) { return Visit(T.getElementLoc()); } TypeLoc VisitFunctionTypeLoc(FunctionTypeLoc T) { return Visit(T.getReturnLoc()); } TypeLoc VisitParenTypeLoc(ParenTypeLoc T) { return Visit(T.getInnerLoc()); } TypeLoc VisitAttributedTypeLoc(AttributedTypeLoc T) { return Visit(T.getModifiedLoc()); } TypeLoc VisitMacroQualifiedTypeLoc(MacroQualifiedTypeLoc T) { return Visit(T.getInnerLoc()); } TypeLoc VisitAdjustedTypeLoc(AdjustedTypeLoc T) { return Visit(T.getOriginalLoc()); } TypeLoc VisitPackExpansionTypeLoc(PackExpansionTypeLoc T) { return Visit(T.getPatternLoc()); } }; } // namespace AutoTypeLoc TypeLoc::getContainedAutoTypeLoc() const { TypeLoc Res = GetContainedAutoTypeLocVisitor().Visit(*this); if (Res.isNull()) return AutoTypeLoc(); return Res.getAs(); }