diff options
author | Douglas Gregor <dgregor@apple.com> | 2009-10-13 21:16:44 +0000 |
---|---|---|
committer | Douglas Gregor <dgregor@apple.com> | 2009-10-13 21:16:44 +0000 |
commit | 3f09327b26033d0a9676d52d80cf92c48f581aff (patch) | |
tree | 039a1889fa3bd411d947c5642da2182868e05489 /lib/Sema | |
parent | cee1b54e11cb4d460634e6ecedbe75c7c2382389 (diff) |
Unify our diagnostic printing for errors of the form, "we didn't like
what we found when we looked into <blah>", where <blah> is a
DeclContext*. We can now format DeclContext*'s in nice ways, e.g.,
"namespace N", "the global namespace", "'class Foo'".
This is part of PR3990, but we're not quite there yet.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@84028 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/Sema.cpp | 157 | ||||
-rw-r--r-- | lib/Sema/Sema.h | 3 | ||||
-rw-r--r-- | lib/Sema/SemaCXXScopeSpec.cpp | 4 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 9 | ||||
-rw-r--r-- | lib/Sema/SemaDeclCXX.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 19 | ||||
-rw-r--r-- | lib/Sema/SemaTemplate.cpp | 10 |
7 files changed, 107 insertions, 98 deletions
diff --git a/lib/Sema/Sema.cpp b/lib/Sema/Sema.cpp index 3aae2563d1..c289abfea8 100644 --- a/lib/Sema/Sema.cpp +++ b/lib/Sema/Sema.cpp @@ -23,6 +23,54 @@ #include "clang/Basic/TargetInfo.h" using namespace clang; +/// \brief Convert the given type to a string suitable for printing as part of +/// a diagnostic. +/// +/// \param Context the context in which the type was allocated +/// \param Ty the type to print +static std::string ConvertTypeToDiagnosticString(ASTContext &Context, + QualType Ty) { + // FIXME: Playing with std::string is really slow. + std::string S = Ty.getAsString(Context.PrintingPolicy); + + // If this is a sugared type (like a typedef, typeof, etc), then unwrap one + // level of the sugar so that the type is more obvious to the user. + QualType DesugaredTy = Ty.getDesugaredType(); + + if (Ty != DesugaredTy && + // 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". + !isa<VectorType>(DesugaredTy) && + + // Don't aka just because we saw an elaborated type... + (!isa<ElaboratedType>(Ty) || + cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) && + + // ...or a qualified name type... + (!isa<QualifiedNameType>(Ty) || + cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) && + + // ...or a non-dependent template specialization. + (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) && + + // Don't desugar magic Objective-C types. + Ty.getUnqualifiedType() != Context.getObjCIdType() && + Ty.getUnqualifiedType() != Context.getObjCClassType() && + Ty.getUnqualifiedType() != Context.getObjCSelType() && + Ty.getUnqualifiedType() != Context.getObjCProtoType() && + + // Not va_list. + Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { + S = "'"+S+"' (aka '"; + S += DesugaredTy.getAsString(Context.PrintingPolicy); + S += "')"; + return S; + } + + S = "'" + S + "'"; + return S; +} + /// ConvertQualTypeToStringFn - This function is used to pretty print the /// specified QualType as a string in diagnostics. static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, @@ -33,50 +81,14 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, ASTContext &Context = *static_cast<ASTContext*>(Cookie); std::string S; + bool NeedQuotes = true; if (Kind == Diagnostic::ak_qualtype) { assert(ModLen == 0 && ArgLen == 0 && "Invalid modifier for QualType argument"); QualType Ty(QualType::getFromOpaquePtr(reinterpret_cast<void*>(Val))); - - // FIXME: Playing with std::string is really slow. - S = Ty.getAsString(Context.PrintingPolicy); - - // If this is a sugared type (like a typedef, typeof, etc), then unwrap one - // level of the sugar so that the type is more obvious to the user. - QualType DesugaredTy = Ty.getDesugaredType(); - - if (Ty != DesugaredTy && - // 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". - !isa<VectorType>(DesugaredTy) && - - // Don't aka just because we saw an elaborated type... - (!isa<ElaboratedType>(Ty) || - cast<ElaboratedType>(Ty)->desugar() != DesugaredTy) && - - // ...or a qualified name type... - (!isa<QualifiedNameType>(Ty) || - cast<QualifiedNameType>(Ty)->desugar() != DesugaredTy) && - - // ...or a non-dependent template specialization. - (!isa<TemplateSpecializationType>(Ty) || Ty->isDependentType()) && - - // Don't desugar magic Objective-C types. - Ty.getUnqualifiedType() != Context.getObjCIdType() && - Ty.getUnqualifiedType() != Context.getObjCClassType() && - Ty.getUnqualifiedType() != Context.getObjCSelType() && - Ty.getUnqualifiedType() != Context.getObjCProtoType() && - - // Not va_list. - Ty.getUnqualifiedType() != Context.getBuiltinVaListType()) { - S = "'"+S+"' (aka '"; - S += DesugaredTy.getAsString(Context.PrintingPolicy); - S += "')"; - Output.append(S.begin(), S.end()); - return; - } - + S = ConvertTypeToDiagnosticString(Context, Ty); + NeedQuotes = false; } else if (Kind == Diagnostic::ak_declarationname) { DeclarationName N = DeclarationName::getFromOpaqueInteger(Val); @@ -101,16 +113,50 @@ static void ConvertArgToStringFn(Diagnostic::ArgumentKind Kind, intptr_t Val, reinterpret_cast<NamedDecl*>(Val)->getNameForDiagnostic(S, Context.PrintingPolicy, Qualified); - } else { + } else if (Kind == Diagnostic::ak_nestednamespec) { llvm::raw_string_ostream OS(S); - assert(Kind == Diagnostic::ak_nestednamespec); reinterpret_cast<NestedNameSpecifier*> (Val)->print(OS, Context.PrintingPolicy); + } else { + assert(Kind == Diagnostic::ak_declcontext); + DeclContext *DC = reinterpret_cast<DeclContext *> (Val); + NeedQuotes = false; + if (!DC) { + assert(false && "Should never have a null declaration context"); + S = "unknown context"; + } else 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)); + NeedQuotes = false; + } 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; + } } - Output.push_back('\''); + if (NeedQuotes) + Output.push_back('\''); + Output.append(S.begin(), S.end()); - Output.push_back('\''); + + if (NeedQuotes) + Output.push_back('\''); } @@ -363,31 +409,6 @@ NamedDecl *Sema::getCurFunctionOrMethodDecl() { return 0; } -void Sema::DiagnoseMissingMember(SourceLocation MemberLoc, - DeclarationName Member, - NestedNameSpecifier *NNS, SourceRange Range) { - switch (NNS->getKind()) { - default: assert(0 && "Unexpected nested name specifier kind!"); - case NestedNameSpecifier::TypeSpec: { - const Type *Ty = Context.getCanonicalType(NNS->getAsType()); - RecordDecl *RD = cast<RecordType>(Ty)->getDecl(); - Diag(MemberLoc, diag::err_typecheck_record_no_member) - << Member << RD->getTagKind() << RD << Range; - break; - } - case NestedNameSpecifier::Namespace: { - Diag(MemberLoc, diag::err_typecheck_namespace_no_member) - << Member << NNS->getAsNamespace() << Range; - break; - } - case NestedNameSpecifier::Global: { - Diag(MemberLoc, diag::err_typecheck_global_namespace_no_member) - << Member << Range; - break; - } - } -} - Sema::SemaDiagnosticBuilder::~SemaDiagnosticBuilder() { if (!this->Emit()) return; diff --git a/lib/Sema/Sema.h b/lib/Sema/Sema.h index fed2fbc081..465eca70ed 100644 --- a/lib/Sema/Sema.h +++ b/lib/Sema/Sema.h @@ -3720,9 +3720,6 @@ public: QualType FieldTy, const Expr *BitWidth, bool *ZeroWidth = 0); - void DiagnoseMissingMember(SourceLocation MemberLoc, DeclarationName Member, - NestedNameSpecifier *NNS, SourceRange Range); - /// adjustFunctionParamType - Converts the type of a function parameter to a // type that can be passed as an argument type to /// ASTContext::getFunctionType. diff --git a/lib/Sema/SemaCXXScopeSpec.cpp b/lib/Sema/SemaCXXScopeSpec.cpp index 911cf67770..10c138c755 100644 --- a/lib/Sema/SemaCXXScopeSpec.cpp +++ b/lib/Sema/SemaCXXScopeSpec.cpp @@ -471,9 +471,7 @@ Sema::CXXScopeTy *Sema::BuildCXXNestedNameSpecifier(Scope *S, if (SD) DiagID = diag::err_expected_class_or_namespace; else if (SS.isSet()) { - DiagnoseMissingMember(IdLoc, DeclarationName(&II), - (NestedNameSpecifier *)SS.getScopeRep(), - SS.getRange()); + Diag(IdLoc, diag::err_no_member) << &II << LookupCtx << SS.getRange(); return 0; } else DiagID = diag::err_undeclared_var_use; diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index a1582a900f..9f03cb284c 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2229,10 +2229,9 @@ Sema::ActOnVariableDeclarator(Scope* S, Declarator& D, DeclContext* DC, } } else if (D.getCXXScopeSpec().isSet()) { // No previous declaration in the qualifying scope. - NestedNameSpecifier *NNS = - (NestedNameSpecifier *)D.getCXXScopeSpec().getScopeRep(); - DiagnoseMissingMember(D.getIdentifierLoc(), Name, NNS, - D.getCXXScopeSpec().getRange()); + Diag(D.getIdentifierLoc(), diag::err_no_member) + << Name << computeDeclContext(D.getCXXScopeSpec(), true) + << D.getCXXScopeSpec().getRange(); NewVD->setInvalidDecl(); } @@ -2844,7 +2843,7 @@ Sema::ActOnFunctionDeclarator(Scope* S, Declarator& D, DeclContext* DC, // matches (e.g., those that differ only in cv-qualifiers and // whether the parameter types are references). Diag(D.getIdentifierLoc(), diag::err_member_def_does_not_match) - << cast<NamedDecl>(DC) << D.getCXXScopeSpec().getRange(); + << Name << DC << D.getCXXScopeSpec().getRange(); NewFD->setInvalidDecl(); LookupResult Prev; diff --git a/lib/Sema/SemaDeclCXX.cpp b/lib/Sema/SemaDeclCXX.cpp index 646ac75dd3..82cdd2f57a 100644 --- a/lib/Sema/SemaDeclCXX.cpp +++ b/lib/Sema/SemaDeclCXX.cpp @@ -2767,7 +2767,8 @@ NamedDecl *Sema::BuildUsingDeclaration(SourceLocation UsingLoc, LookupQualifiedName(R, LookupContext, Name, LookupOrdinaryName); if (R.empty()) { - DiagnoseMissingMember(IdentLoc, Name, NNS, SS.getRange()); + Diag(IdentLoc, diag::err_no_member) + << Name << LookupContext << SS.getRange(); return 0; } diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index b7c2308541..194317ce23 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -802,12 +802,11 @@ Sema::ActOnDeclarationNameExpr(Scope *S, SourceLocation Loc, else { // If this name wasn't predeclared and if this is not a function call, // diagnose the problem. - if (SS && !SS->isEmpty()) { - DiagnoseMissingMember(Loc, Name, - (NestedNameSpecifier *)SS->getScopeRep(), - SS->getRange()); - return ExprError(); - } else if (Name.getNameKind() == DeclarationName::CXXOperatorName || + if (SS && !SS->isEmpty()) + return ExprError(Diag(Loc, diag::err_no_member) + << Name << computeDeclContext(*SS, false) + << SS->getRange()); + else if (Name.getNameKind() == DeclarationName::CXXOperatorName || Name.getNameKind() == DeclarationName::CXXConversionFunctionName) return ExprError(Diag(Loc, diag::err_undeclared_use) << Name.getAsString()); @@ -2185,8 +2184,8 @@ Sema::BuildMemberReferenceExpr(Scope *S, ExprArg Base, SourceLocation OpLoc, LookupQualifiedName(Result, DC, MemberName, LookupMemberName, false); if (Result.empty()) - return ExprError(Diag(MemberLoc, diag::err_typecheck_no_member_deprecated) - << MemberName << BaseExpr->getSourceRange()); + return ExprError(Diag(MemberLoc, diag::err_no_member) + << MemberName << DC << BaseExpr->getSourceRange()); if (Result.isAmbiguous()) { DiagnoseAmbiguousLookup(Result, MemberName, MemberLoc, BaseExpr->getSourceRange()); @@ -5689,8 +5688,8 @@ Sema::OwningExprResult Sema::ActOnBuiltinOffsetOf(Scope *S, = dyn_cast_or_null<FieldDecl>(R.getAsSingleDecl(Context)); // FIXME: Leaks Res if (!MemberDecl) - return ExprError(Diag(BuiltinLoc, diag::err_typecheck_no_member_deprecated) - << OC.U.IdentInfo << SourceRange(OC.LocStart, OC.LocEnd)); + return ExprError(Diag(BuiltinLoc, diag::err_no_member) + << OC.U.IdentInfo << RD << SourceRange(OC.LocStart, OC.LocEnd)); // FIXME: C++: Verify that MemberDecl isn't a static field. // FIXME: Verify that MemberDecl isn't a bitfield. diff --git a/lib/Sema/SemaTemplate.cpp b/lib/Sema/SemaTemplate.cpp index 3ee15a5b4d..4a410ecb14 100644 --- a/lib/Sema/SemaTemplate.cpp +++ b/lib/Sema/SemaTemplate.cpp @@ -3903,10 +3903,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, Decl *Referenced = 0; switch (Result.getKind()) { case LookupResult::NotFound: - if (Ctx->isTranslationUnit()) - DiagID = diag::err_typename_nested_not_found_global; - else - DiagID = diag::err_typename_nested_not_found; + DiagID = diag::err_typename_nested_not_found; break; case LookupResult::Found: @@ -3933,10 +3930,7 @@ Sema::CheckTypenameType(NestedNameSpecifier *NNS, const IdentifierInfo &II, // If we get here, it's because name lookup did not find a // type. Emit an appropriate diagnostic and return an error. - if (NamedDecl *NamedCtx = dyn_cast<NamedDecl>(Ctx)) - Diag(Range.getEnd(), DiagID) << Range << Name << NamedCtx; - else - Diag(Range.getEnd(), DiagID) << Range << Name; + Diag(Range.getEnd(), DiagID) << Range << Name << Ctx; if (Referenced) Diag(Referenced->getLocation(), diag::note_typename_refers_here) << Name; |