| //===--- TypeLoc.cpp - Type Source Info Wrapper -----------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file defines the TypeLoc subclasses implementations. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/AST/TypeLoc.h" |
| #include "clang/AST/ASTContext.h" |
| #include "clang/AST/Expr.h" |
| #include "clang/AST/TypeLocVisitor.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include "llvm/Support/raw_ostream.h" |
| using namespace clang; |
| |
| //===----------------------------------------------------------------------===// |
| // TypeLoc Implementation |
| //===----------------------------------------------------------------------===// |
| |
| namespace { |
| class TypeLocRanger : public TypeLocVisitor<TypeLocRanger, SourceRange> { |
| 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" |
| }; |
| } |
| |
| SourceRange TypeLoc::getLocalSourceRangeImpl(TypeLoc TL) { |
| if (TL.isNull()) return SourceRange(); |
| return TypeLocRanger().Visit(TL); |
| } |
| |
| namespace { |
| class TypeAligner : public TypeLocVisitor<TypeAligner, unsigned> { |
| 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" |
| }; |
| } |
| |
| /// \brief 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, 0)); |
| } |
| |
| namespace { |
| class TypeSizer : public TypeLocVisitor<TypeSizer, unsigned> { |
| 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" |
| }; |
| } |
| |
| /// \brief Returns the size of the type source info data block. |
| unsigned TypeLoc::getFullDataSizeForType(QualType Ty) { |
| unsigned Total = 0; |
| TypeLoc TyLoc(Ty, 0); |
| unsigned MaxAlign = 1; |
| while (!TyLoc.isNull()) { |
| unsigned Align = getLocalAlignmentForType(TyLoc.getType()); |
| MaxAlign = std::max(Align, MaxAlign); |
| Total = llvm::RoundUpToAlignment(Total, Align); |
| Total += TypeSizer().Visit(TyLoc); |
| TyLoc = TyLoc.getNextTypeLoc(); |
| } |
| Total = llvm::RoundUpToAlignment(Total, MaxAlign); |
| return Total; |
| } |
| |
| namespace { |
| class NextLoc : public TypeLocVisitor<NextLoc, TypeLoc> { |
| 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" |
| }; |
| } |
| |
| /// \brief 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); |
| } |
| |
| /// \brief 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<CLASS##TypeLoc>(); \ |
| TLCasted.initializeLocal(Context, Loc); \ |
| TL = TLCasted.getNextTypeLoc(); \ |
| if (!TL) return; \ |
| continue; \ |
| } |
| #include "clang/AST/TypeLocNodes.def" |
| } |
| } |
| } |
| |
| 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<FunctionProtoTypeLoc>().getTypePtr() |
| ->hasTrailingReturn()) { |
| LeftMost = Cur; |
| break; |
| } |
| /* Fall through */ |
| 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().isInvalid()) |
| 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<FunctionProtoTypeLoc>().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<TSTChecker, bool> { |
| // 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" |
| }; |
| } |
| |
| |
| /// \brief 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); |
| } |
| |
| // 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<TypeSpecifierType>(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::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: |
| 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: |
| case BuiltinType::OCLImage1d: |
| case BuiltinType::OCLImage1dArray: |
| case BuiltinType::OCLImage1dBuffer: |
| case BuiltinType::OCLImage2d: |
| case BuiltinType::OCLImage2dArray: |
| case BuiltinType::OCLImage3d: |
| case BuiltinType::OCLSampler: |
| case BuiltinType::OCLEvent: |
| case BuiltinType::BuiltinFn: |
| return TST_unspecified; |
| } |
| |
| llvm_unreachable("Invalid BuiltinType Kind!"); |
| } |
| |
| TypeLoc TypeLoc::IgnoreParensImpl(TypeLoc TL) { |
| while (ParenTypeLoc PTL = TL.getAs<ParenTypeLoc>()) |
| TL = PTL.getInnerLoc(); |
| return TL; |
| } |
| |
| 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; |
| } |
| } |
| } |