diff options
Diffstat (limited to 'lib/AST/APValue.cpp')
-rw-r--r-- | lib/AST/APValue.cpp | 249 |
1 files changed, 192 insertions, 57 deletions
diff --git a/lib/AST/APValue.cpp b/lib/AST/APValue.cpp index b99a66267c..0d4dea82cc 100644 --- a/lib/AST/APValue.cpp +++ b/lib/AST/APValue.cpp @@ -12,7 +12,11 @@ //===----------------------------------------------------------------------===// #include "clang/AST/APValue.h" +#include "clang/AST/ASTContext.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/DeclCXX.h" +#include "clang/AST/Expr.h" +#include "clang/AST/Type.h" #include "clang/Basic/Diagnostic.h" #include "llvm/ADT/SmallString.h" #include "llvm/Support/raw_ostream.h" @@ -203,7 +207,7 @@ void APValue::MakeUninit() { } void APValue::dump() const { - print(llvm::errs()); + dump(llvm::errs()); llvm::errs() << '\n'; } @@ -215,7 +219,7 @@ static double GetApproxValue(const llvm::APFloat &F) { return V.convertToDouble(); } -void APValue::print(raw_ostream &OS) const { +void APValue::dump(raw_ostream &OS) const { switch (getKind()) { case Uninitialized: OS << "Uninitialized"; @@ -227,9 +231,12 @@ void APValue::print(raw_ostream &OS) const { OS << "Float: " << GetApproxValue(getFloat()); return; case Vector: - OS << "Vector: " << getVectorElt(0); - for (unsigned i = 1; i != getVectorLength(); ++i) - OS << ", " << getVectorElt(i); + OS << "Vector: "; + getVectorElt(0).dump(OS); + for (unsigned i = 1; i != getVectorLength(); ++i) { + OS << ", "; + getVectorElt(i).dump(OS); + } return; case ComplexInt: OS << "ComplexInt: " << getComplexIntReal() << ", " << getComplexIntImag(); @@ -244,28 +251,36 @@ void APValue::print(raw_ostream &OS) const { case Array: OS << "Array: "; for (unsigned I = 0, N = getArrayInitializedElts(); I != N; ++I) { - OS << getArrayInitializedElt(I); + getArrayInitializedElt(I).dump(OS); if (I != getArraySize() - 1) OS << ", "; } - if (hasArrayFiller()) - OS << getArraySize() - getArrayInitializedElts() << " x " - << getArrayFiller(); + if (hasArrayFiller()) { + OS << getArraySize() - getArrayInitializedElts() << " x "; + getArrayFiller().dump(OS); + } return; case Struct: OS << "Struct "; if (unsigned N = getStructNumBases()) { - OS << " bases: " << getStructBase(0); - for (unsigned I = 1; I != N; ++I) - OS << ", " << getStructBase(I); + OS << " bases: "; + getStructBase(0).dump(OS); + for (unsigned I = 1; I != N; ++I) { + OS << ", "; + getStructBase(I).dump(OS); + } } if (unsigned N = getStructNumFields()) { - OS << " fields: " << getStructField(0); - for (unsigned I = 1; I != N; ++I) - OS << ", " << getStructField(I); + OS << " fields: "; + getStructField(0).dump(OS); + for (unsigned I = 1; I != N; ++I) { + OS << ", "; + getStructField(I).dump(OS); + } } return; case Union: - OS << "Union: " << getUnionValue(); + OS << "Union: "; + getUnionValue().dump(OS); return; case MemberPointer: OS << "MemberPointer: <todo>"; @@ -274,78 +289,198 @@ void APValue::print(raw_ostream &OS) const { llvm_unreachable("Unknown APValue kind!"); } -static void WriteShortAPValueToStream(raw_ostream& Out, - const APValue& V) { - switch (V.getKind()) { +void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ + switch (getKind()) { case APValue::Uninitialized: - Out << "Uninitialized"; + Out << "<uninitialized>"; return; case APValue::Int: - Out << V.getInt(); + Out << getInt(); return; case APValue::Float: - Out << GetApproxValue(V.getFloat()); + Out << GetApproxValue(getFloat()); return; - case APValue::Vector: - Out << '['; - WriteShortAPValueToStream(Out, V.getVectorElt(0)); - for (unsigned i = 1; i != V.getVectorLength(); ++i) { + case APValue::Vector: { + Out << '{'; + QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); + getVectorElt(0).printPretty(Out, Ctx, ElemTy); + for (unsigned i = 1; i != getVectorLength(); ++i) { Out << ", "; - WriteShortAPValueToStream(Out, V.getVectorElt(i)); + getVectorElt(i).printPretty(Out, Ctx, ElemTy); } - Out << ']'; + Out << '}'; return; + } case APValue::ComplexInt: - Out << V.getComplexIntReal() << "+" << V.getComplexIntImag() << "i"; + Out << getComplexIntReal() << "+" << getComplexIntImag() << "i"; return; case APValue::ComplexFloat: - Out << GetApproxValue(V.getComplexFloatReal()) << "+" - << GetApproxValue(V.getComplexFloatImag()) << "i"; + Out << GetApproxValue(getComplexFloatReal()) << "+" + << GetApproxValue(getComplexFloatImag()) << "i"; return; - case APValue::LValue: - Out << "LValue: <todo>"; + case APValue::LValue: { + LValueBase Base = getLValueBase(); + if (!Base) { + Out << "0"; + return; + } + + bool IsReference = Ty->isReferenceType(); + QualType InnerTy + = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); + + if (!hasLValuePath()) { + // No lvalue path: just print the offset. + CharUnits O = getLValueOffset(); + CharUnits S = Ctx.getTypeSizeInChars(InnerTy); + if (!O.isZero()) { + if (IsReference) + Out << "*("; + if (O % S) { + Out << "(char*)"; + S = CharUnits::One(); + } + Out << '&'; + } else if (!IsReference) + Out << '&'; + + if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) + Out << *VD; + else + Base.get<const Expr*>()->printPretty(Out, Ctx, 0, + Ctx.getPrintingPolicy()); + if (!O.isZero()) { + Out << " + " << (O / S); + if (IsReference) + Out << ')'; + } + return; + } + + // We have an lvalue path. Print it out nicely. + if (!IsReference) + Out << '&'; + else if (isLValueOnePastTheEnd()) + Out << "*(&"; + + QualType ElemTy; + if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { + Out << *VD; + ElemTy = VD->getType(); + } else { + const Expr *E = Base.get<const Expr*>(); + E->printPretty(Out, Ctx, 0,Ctx.getPrintingPolicy()); + ElemTy = E->getType(); + } + + ArrayRef<LValuePathEntry> Path = getLValuePath(); + const CXXRecordDecl *CastToBase = 0; + for (unsigned I = 0, N = Path.size(); I != N; ++I) { + if (ElemTy->getAs<RecordType>()) { + // The lvalue refers to a class type, so the next path entry is a base + // or member. + const Decl *BaseOrMember = + BaseOrMemberType::getFromOpaqueValue(Path[I].BaseOrMember).getPointer(); + if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { + CastToBase = RD; + ElemTy = Ctx.getRecordType(RD); + } else { + const ValueDecl *VD = cast<ValueDecl>(BaseOrMember); + Out << "."; + if (CastToBase) + Out << *CastToBase << "::"; + Out << *VD; + ElemTy = VD->getType(); + } + } else { + // The lvalue must refer to an array. + Out << '[' << Path[I].ArrayIndex << ']'; + ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); + } + } + + // Handle formatting of one-past-the-end lvalues. + if (isLValueOnePastTheEnd()) { + // FIXME: If CastToBase is non-0, we should prefix the output with + // "(CastToBase*)". + Out << " + 1"; + if (IsReference) + Out << ')'; + } return; - case APValue::Array: + } + case APValue::Array: { + const ArrayType *AT = Ctx.getAsArrayType(Ty); + QualType ElemTy = AT->getElementType(); Out << '{'; - if (unsigned N = V.getArrayInitializedElts()) { - Out << V.getArrayInitializedElt(0); - for (unsigned I = 1; I != N; ++I) - Out << ", " << V.getArrayInitializedElt(I); + if (unsigned N = getArrayInitializedElts()) { + getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy); + for (unsigned I = 1; I != N; ++I) { + Out << ", "; + if (I == 10) { + // Avoid printing out the entire contents of large arrays. + Out << "..."; + break; + } + getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); + } } Out << '}'; return; - case APValue::Struct: + } + case APValue::Struct: { Out << '{'; - if (unsigned N = V.getStructNumBases()) { - Out << V.getStructBase(0); - for (unsigned I = 1; I != N; ++I) - Out << ", " << V.getStructBase(I); - if (V.getStructNumFields()) - Out << ", "; + const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); + bool First = true; + if (unsigned N = getStructNumBases()) { + const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD); + CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); + for (unsigned I = 0; I != N; ++I, ++BI) { + assert(BI != CD->bases_end()); + if (!First) + Out << ", "; + getStructBase(I).printPretty(Out, Ctx, BI->getType()); + First = false; + } } - if (unsigned N = V.getStructNumFields()) { - Out << V.getStructField(0); - for (unsigned I = 1; I != N; ++I) - Out << ", " << V.getStructField(I); + for (RecordDecl::field_iterator FI = RD->field_begin(); + FI != RD->field_end(); ++FI) { + if (!First) + Out << ", "; + if ((*FI)->isUnnamedBitfield()) continue; + getStructField((*FI)->getFieldIndex()). + printPretty(Out, Ctx, (*FI)->getType()); + First = false; } Out << '}'; return; + } case APValue::Union: - Out << '{' << V.getUnionValue() << '}'; + Out << '{'; + if (const FieldDecl *FD = getUnionField()) { + Out << "." << *FD << " = "; + getUnionValue().printPretty(Out, Ctx, FD->getType()); + } + Out << '}'; return; case APValue::MemberPointer: - Out << "MemberPointer: <todo>"; + // FIXME: This is not enough to unambiguously identify the member in a + // multiple-inheritance scenario. + if (const ValueDecl *VD = getMemberPointerDecl()) { + Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD; + return; + } + Out << "0"; return; } llvm_unreachable("Unknown APValue kind!"); } -const DiagnosticBuilder &clang::operator<<(const DiagnosticBuilder &DB, - const APValue &V) { - llvm::SmallString<64> Buffer; - llvm::raw_svector_ostream Out(Buffer); - WriteShortAPValueToStream(Out, V); - return DB << Out.str(); +std::string APValue::getAsString(ASTContext &Ctx, QualType Ty) const { + std::string Result; + llvm::raw_string_ostream Out(Result); + printPretty(Out, Ctx, Ty); + return Result; } const APValue::LValueBase APValue::getLValueBase() const { |