aboutsummaryrefslogtreecommitdiff
path: root/lib/AST/APValue.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/AST/APValue.cpp')
-rw-r--r--lib/AST/APValue.cpp249
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 {