diff options
Diffstat (limited to 'contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp')
-rw-r--r-- | contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp | 265 |
1 files changed, 265 insertions, 0 deletions
diff --git a/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp new file mode 100644 index 0000000..0d609bf --- /dev/null +++ b/contrib/llvm/tools/clang/lib/AST/ASTDiagnostic.cpp @@ -0,0 +1,265 @@ +//===--- ASTDiagnostic.cpp - Diagnostic Printing Hooks for AST Nodes ------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file implements a diagnostic formatting hook for AST elements. +// +//===----------------------------------------------------------------------===// +#include "clang/AST/ASTDiagnostic.h" + +#include "clang/AST/ASTContext.h" +#include "clang/AST/DeclObjC.h" +#include "clang/AST/Type.h" +#include "llvm/Support/raw_ostream.h" + +using namespace clang; + +// Returns a desugared version of the QualType, and marks ShouldAKA as true +// whenever we remove significant sugar from the type. +static QualType Desugar(ASTContext &Context, QualType QT, bool &ShouldAKA) { + QualifierCollector QC; + + while (true) { + const Type *Ty = QC.strip(QT); + + // Don't aka just because we saw an elaborated type... + if (isa<ElaboratedType>(Ty)) { + QT = cast<ElaboratedType>(Ty)->desugar(); + continue; + } + + // ...or a substituted template type parameter. + if (isa<SubstTemplateTypeParmType>(Ty)) { + QT = cast<SubstTemplateTypeParmType>(Ty)->desugar(); + continue; + } + + // Don't desugar template specializations. + if (isa<TemplateSpecializationType>(Ty)) + break; + + // Don't desugar magic Objective-C types. + if (QualType(Ty,0) == Context.getObjCIdType() || + QualType(Ty,0) == Context.getObjCClassType() || + QualType(Ty,0) == Context.getObjCSelType() || + QualType(Ty,0) == Context.getObjCProtoType()) + break; + + // Don't desugar va_list. + if (QualType(Ty,0) == Context.getBuiltinVaListType()) + break; + + // Otherwise, do a single-step desugar. + QualType Underlying; + bool IsSugar = false; + switch (Ty->getTypeClass()) { +#define ABSTRACT_TYPE(Class, Base) +#define TYPE(Class, Base) \ +case Type::Class: { \ +const Class##Type *CTy = cast<Class##Type>(Ty); \ +if (CTy->isSugared()) { \ +IsSugar = true; \ +Underlying = CTy->desugar(); \ +} \ +break; \ +} +#include "clang/AST/TypeNodes.def" + } + + // If it wasn't sugared, we're done. + if (!IsSugar) + break; + + // If the desugared type is a vector type, we don't want to expand + // it, it will turn into an attribute mess. People want their "vec4". + if (isa<VectorType>(Underlying)) + break; + + // Don't desugar through the primary typedef of an anonymous type. + if (isa<TagType>(Underlying) && isa<TypedefType>(QT)) + if (cast<TagType>(Underlying)->getDecl()->getTypedefForAnonDecl() == + cast<TypedefType>(QT)->getDecl()) + break; + + // Record that we actually looked through an opaque type here. + ShouldAKA = true; + QT = Underlying; + } + + // If we have a pointer-like type, desugar the pointee as well. + // FIXME: Handle other pointer-like types. + if (const PointerType *Ty = QT->getAs<PointerType>()) { + QT = Context.getPointerType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); + } else if (const LValueReferenceType *Ty = QT->getAs<LValueReferenceType>()) { + QT = Context.getLValueReferenceType(Desugar(Context, Ty->getPointeeType(), + ShouldAKA)); + } + + return QC.apply(QT); +} + +/// \brief Convert the given type to a string suitable for printing as part of +/// a diagnostic. +/// +/// There are three main criteria when determining whether we should have an +/// a.k.a. clause when pretty-printing a type: +/// +/// 1) Some types provide very minimal sugar that doesn't impede the +/// user's understanding --- for example, elaborated type +/// specifiers. If this is all the sugar we see, we don't want an +/// a.k.a. clause. +/// 2) Some types are technically sugared but are much more familiar +/// when seen in their sugared form --- for example, va_list, +/// vector types, and the magic Objective C types. We don't +/// want to desugar these, even if we do produce an a.k.a. clause. +/// 3) Some types may have already been desugared previously in this diagnostic. +/// if this is the case, doing another "aka" would just be clutter. +/// +/// \param Context the context in which the type was allocated +/// \param Ty the type to print +static std::string +ConvertTypeToDiagnosticString(ASTContext &Context, QualType Ty, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs) { + // FIXME: Playing with std::string is really slow. + std::string S = Ty.getAsString(Context.PrintingPolicy); + + // Check to see if we already desugared this type in this + // diagnostic. If so, don't do it again. + bool Repeated = false; + for (unsigned i = 0; i != NumPrevArgs; ++i) { + // TODO: Handle ak_declcontext case. + if (PrevArgs[i].first == Diagnostic::ak_qualtype) { + void *Ptr = (void*)PrevArgs[i].second; + QualType PrevTy(QualType::getFromOpaquePtr(Ptr)); + if (PrevTy == Ty) { + Repeated = true; + break; + } + } + } + + // Consider producing an a.k.a. clause if removing all the direct + // sugar gives us something "significantly different". + if (!Repeated) { + bool ShouldAKA = false; + QualType DesugaredTy = Desugar(Context, Ty, ShouldAKA); + if (ShouldAKA) { + S = "'"+S+"' (aka '"; + S += DesugaredTy.getAsString(Context.PrintingPolicy); + S += "')"; + return S; + } + } + + S = "'" + S + "'"; + return S; +} + +void clang::FormatASTNodeDiagnosticArgument(Diagnostic::ArgumentKind Kind, + intptr_t Val, + const char *Modifier, + unsigned ModLen, + const char *Argument, + unsigned ArgLen, + const Diagnostic::ArgumentValue *PrevArgs, + unsigned NumPrevArgs, + llvm::SmallVectorImpl<char> &Output, + void *Cookie) { + ASTContext &Context = *static_cast<ASTContext*>(Cookie); + + std::string S; + bool NeedQuotes = true; + + switch (Kind) { + default: assert(0 && "unknown ArgumentKind"); + case Diagnostic::ak_qualtype: { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for QualType argument"); + + QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); + S = ConvertTypeToDiagnosticString(Context, Ty, PrevArgs, NumPrevArgs); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declarationname: { + DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); + S = N.getAsString(); + + if (ModLen == 9 && !memcmp(Modifier, "objcclass", 9) && ArgLen == 0) + S = '+' + S; + else if (ModLen == 12 && !memcmp(Modifier, "objcinstance", 12) + && ArgLen==0) + S = '-' + S; + else + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for DeclarationName argument"); + break; + } + case Diagnostic::ak_nameddecl: { + bool Qualified; + if (ModLen == 1 && Modifier[0] == 'q' && ArgLen == 0) + Qualified = true; + else { + assert(ModLen == 0 && ArgLen == 0 && + "Invalid modifier for NamedDecl* argument"); + Qualified = false; + } + reinterpret_cast<NamedDecl*>(Val)-> + getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); + break; + } + case Diagnostic::ak_nestednamespec: { + llvm::raw_string_ostream OS(S); + reinterpret_cast<NestedNameSpecifier*>(Val)->print(OS, + Context.PrintingPolicy); + NeedQuotes = false; + break; + } + case Diagnostic::ak_declcontext: { + DeclContext *DC = reinterpret_cast<DeclContext *> (Val); + assert(DC && "Should never have a null declaration context"); + + if (DC->isTranslationUnit()) { + // FIXME: Get these strings from some localized place + if (Context.getLangOptions().CPlusPlus) + S = "the global namespace"; + else + S = "the global scope"; + } else if (TypeDecl *Type = dyn_cast<TypeDecl>(DC)) { + S = ConvertTypeToDiagnosticString(Context, + Context.getTypeDeclType(Type), + PrevArgs, NumPrevArgs); + } else { + // FIXME: Get these strings from some localized place + NamedDecl *ND = cast<NamedDecl>(DC); + if (isa<NamespaceDecl>(ND)) + S += "namespace "; + else if (isa<ObjCMethodDecl>(ND)) + S += "method "; + else if (isa<FunctionDecl>(ND)) + S += "function "; + + S += "'"; + ND->getNameForDiagnostic(S, Context.PrintingPolicy, true); + S += "'"; + } + NeedQuotes = false; + break; + } + } + + if (NeedQuotes) + Output.push_back('\''); + + Output.append(S.begin(), S.end()); + + if (NeedQuotes) + Output.push_back('\''); +} |