Typo correction for C++ base and member initializers, e.g.,

test/FixIt/typo.cpp:41:15: error: initializer 'base' does not name a non-static
      data member or base class; did you mean the base class 'Base'?
  Derived() : base(),
              ^~~~
              Base
test/FixIt/typo.cpp:42:15: error: initializer 'ember' does not name a non-static
      data member or base class; did you mean the member 'member'?
              ember() { }
              ^~~~~
              member

llvm-svn: 92355
This commit is contained in:
Douglas Gregor 2009-12-31 09:10:24 +00:00
parent 4e3a5678af
commit 15e77a2fd3
3 changed files with 99 additions and 32 deletions

View File

@ -2560,6 +2560,9 @@ def err_undeclared_var_use_suggest : Error<
def err_no_template_suggest : Error<"no template named %0; did you mean %1?">;
def err_no_member_template_suggest : Error<
"no template named %0 in %1; did you mean %2?">;
def err_mem_init_not_member_or_class_suggest : Error<
"initializer %0 does not name a non-static data member or base "
"class; did you mean the %select{base class|member}1 %2?">;
}

View File

@ -948,6 +948,51 @@ Sema::ActOnCXXMemberDeclarator(Scope *S, AccessSpecifier AS, Declarator &D,
return DeclPtrTy::make(Member);
}
/// \brief Find the direct and/or virtual base specifiers that
/// correspond to the given base type, for use in base initialization
/// within a constructor.
static bool FindBaseInitializer(Sema &SemaRef,
CXXRecordDecl *ClassDecl,
QualType BaseType,
const CXXBaseSpecifier *&DirectBaseSpec,
const CXXBaseSpecifier *&VirtualBaseSpec) {
// First, check for a direct base class.
DirectBaseSpec = 0;
for (CXXRecordDecl::base_class_const_iterator Base
= ClassDecl->bases_begin();
Base != ClassDecl->bases_end(); ++Base) {
if (SemaRef.Context.hasSameUnqualifiedType(BaseType, Base->getType())) {
// We found a direct base of this type. That's what we're
// initializing.
DirectBaseSpec = &*Base;
break;
}
}
// Check for a virtual base class.
// FIXME: We might be able to short-circuit this if we know in advance that
// there are no virtual bases.
VirtualBaseSpec = 0;
if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
// We haven't found a base yet; search the class hierarchy for a
// virtual base class.
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
if (SemaRef.IsDerivedFrom(SemaRef.Context.getTypeDeclType(ClassDecl),
BaseType, Paths)) {
for (CXXBasePaths::paths_iterator Path = Paths.begin();
Path != Paths.end(); ++Path) {
if (Path->back().Base->isVirtual()) {
VirtualBaseSpec = Path->back().Base;
break;
}
}
}
}
return DirectBaseSpec || VirtualBaseSpec;
}
/// ActOnMemInitializer - Handle a C++ member initializer.
Sema::MemInitResult
Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
@ -1015,9 +1060,46 @@ Sema::ActOnMemInitializer(DeclPtrTy ConstructorD,
if (!TyD) {
if (R.isAmbiguous()) return true;
Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
return true;
// If no results were found, try to correct typos.
if (R.empty() &&
CorrectTypo(R, S, &SS, ClassDecl) && R.isSingleResult()) {
if (FieldDecl *Member = R.getAsSingle<FieldDecl>()) {
if (Member->getDeclContext()->getLookupContext()->Equals(ClassDecl)) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
// member.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << true << R.getLookupName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
return BuildMemberInitializer(Member, (Expr**)Args, NumArgs, IdLoc,
LParenLoc, RParenLoc);
}
} else if (TypeDecl *Type = R.getAsSingle<TypeDecl>()) {
const CXXBaseSpecifier *DirectBaseSpec;
const CXXBaseSpecifier *VirtualBaseSpec;
if (FindBaseInitializer(*this, ClassDecl,
Context.getTypeDeclType(Type),
DirectBaseSpec, VirtualBaseSpec)) {
// We have found a direct or virtual base class with a
// similar name to what was typed; complain and initialize
// that base class.
Diag(R.getNameLoc(), diag::err_mem_init_not_member_or_class_suggest)
<< MemberOrBase << false << R.getLookupName()
<< CodeModificationHint::CreateReplacement(R.getNameLoc(),
R.getLookupName().getAsString());
TyD = Type;
}
}
}
if (!TyD) {
Diag(IdLoc, diag::err_mem_init_not_member_or_class)
<< MemberOrBase << SourceRange(IdLoc, RParenLoc);
return true;
}
}
BaseType = Context.getTypeDeclType(TyD);
@ -1193,37 +1275,11 @@ Sema::BuildBaseInitializer(QualType BaseType, TypeSourceInfo *BaseTInfo,
// mem-initializer-list can initialize a base class using any
// name that denotes that base class type.
// First, check for a direct base class.
// Check for direct and virtual base classes.
const CXXBaseSpecifier *DirectBaseSpec = 0;
for (CXXRecordDecl::base_class_const_iterator Base =
ClassDecl->bases_begin(); Base != ClassDecl->bases_end(); ++Base) {
if (Context.hasSameUnqualifiedType(BaseType, Base->getType())) {
// We found a direct base of this type. That's what we're
// initializing.
DirectBaseSpec = &*Base;
break;
}
}
// Check for a virtual base class.
// FIXME: We might be able to short-circuit this if we know in advance that
// there are no virtual bases.
const CXXBaseSpecifier *VirtualBaseSpec = 0;
if (!DirectBaseSpec || !DirectBaseSpec->isVirtual()) {
// We haven't found a base yet; search the class hierarchy for a
// virtual base class.
CXXBasePaths Paths(/*FindAmbiguities=*/true, /*RecordPaths=*/true,
/*DetectVirtual=*/false);
if (IsDerivedFrom(Context.getTypeDeclType(ClassDecl), BaseType, Paths)) {
for (CXXBasePaths::paths_iterator Path = Paths.begin();
Path != Paths.end(); ++Path) {
if (Path->back().Base->isVirtual()) {
VirtualBaseSpec = Path->back().Base;
break;
}
}
}
}
FindBaseInitializer(*this, ClassDecl, BaseType, DirectBaseSpec,
VirtualBaseSpec);
// C++ [base.class.init]p2:
// If a mem-initializer-id is ambiguous because it designates both

View File

@ -33,3 +33,11 @@ bool test_string(std::string s) {
return s.fnd("hello") // expected-error{{no member named 'fnd' in 'class std::basic_string<char>'; did you mean 'find'?}}
== std::string::pos; // expected-error{{no member named 'pos' in 'class std::basic_string<char>'; did you mean 'npos'?}}
}
struct Base { };
struct Derived : public Base {
int member;
Derived() : base(), // expected-error{{initializer 'base' does not name a non-static data member or base class; did you mean the base class 'Base'?}}
ember() { } // expected-error{{initializer 'ember' does not name a non-static data member or base class; did you mean the member 'member'?}}
};