// be possible for this to happen, because...?
}
+class UsingValidatorCCC : public CorrectionCandidateCallback {
+public:
+ UsingValidatorCCC(bool IsTypeName, bool IsInstantiation)
+ : IsTypeName(IsTypeName), IsInstantiation(IsInstantiation) {}
+
+ virtual bool ValidateCandidate(const TypoCorrection &Candidate) {
+ if (NamedDecl *ND = Candidate.getCorrectionDecl()) {
+ if (isa<NamespaceDecl>(ND))
+ return false;
+ // Completely unqualified names are invalid for a 'using' declaration.
+ bool droppedSpecifier = Candidate.WillReplaceSpecifier() &&
+ !Candidate.getCorrectionSpecifier();
+ if (droppedSpecifier)
+ return false;
+ else if (isa<TypeDecl>(ND))
+ return IsTypeName || !IsInstantiation;
+ else
+ return !IsTypeName;
+ } else {
+ // Keywords are not valid here.
+ return false;
+ }
+ }
+
+private:
+ bool IsTypeName;
+ bool IsInstantiation;
+};
+
/// Builds a using declaration.
///
/// \param IsInstantiation - Whether this call arises from an
LookupQualifiedName(R, LookupContext);
+ // Try to correct typos if possible.
if (R.empty()) {
- Diag(IdentLoc, diag::err_no_member)
- << NameInfo.getName() << LookupContext << SS.getRange();
- UD->setInvalidDecl();
- return UD;
+ UsingValidatorCCC CCC(IsTypeName, IsInstantiation);
+ if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
+ R.getLookupKind(), S, &SS, CCC)){
+ // We reject any correction for which ND would be NULL.
+ NamedDecl *ND = Corrected.getCorrectionDecl();
+ std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
+ std::string CorrectedQuotedStr(Corrected.getQuoted(getLangOpts()));
+ R.setLookupName(Corrected.getCorrection());
+ R.addDecl(ND);
+ // We reject candidates where droppedSpecifier == true, hence the
+ // literal '0' below.
+ Diag(R.getNameLoc(), diag::err_no_member_suggest)
+ << NameInfo.getName() << LookupContext << 0
+ << CorrectedQuotedStr << SS.getRange()
+ << FixItHint::CreateReplacement(Corrected.getCorrectionRange(),
+ CorrectedStr);
+ Diag(ND->getLocation(), diag::note_previous_decl)
+ << CorrectedQuotedStr;
+ } else {
+ Diag(IdentLoc, diag::err_no_member)
+ << NameInfo.getName() << LookupContext << SS.getRange();
+ UD->setInvalidDecl();
+ return UD;
+ }
}
if (R.isAmbiguous()) {
--- /dev/null
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: cp %s %t
+// RUN: not %clang_cc1 -fsyntax-only -fixit -x c++ %t
+// RUN: %clang_cc1 -fsyntax-only -pedantic -Werror -x c++ %t
+// RUN: grep using_suggestion_tyname_ty_dropped_specifier %t
+
+// These tests have been separated from typo.cpp to keep the maximum typo
+// correction counter from ticking over; this causes spurious failures.
+
+namespace using_suggestion_ty {
+namespace N { class AAA {}; } // expected-note {{'AAA' declared here}}
+using N::AAB; // expected-error {{no member named 'AAB' in namespace 'using_suggestion_ty::N'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_tyname_ty {
+namespace N { class AAA {}; } // expected-note {{'AAA' declared here}}
+using typename N::AAB; // expected-error {{no member named 'AAB' in namespace 'using_suggestion_tyname_ty::N'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_val {
+namespace N { void FFF() {} } // expected-note {{'FFF' declared here}}
+using N::FFG; // expected-error {{no member named 'FFG' in namespace 'using_suggestion_val::N'; did you mean 'FFF'?}}
+}
+
+namespace using_suggestion_ty_dropped_specifier {
+class AAA {}; // expected-note {{'::using_suggestion_ty_dropped_specifier::AAA' declared here}}
+namespace N { }
+using N::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_ty_dropped_specifier::N'; did you mean '::using_suggestion_ty_dropped_specifier::AAA'?}}
+}
+
+namespace using_suggestion_tyname_ty_dropped_specifier {
+class AAA {}; // expected-note {{'::using_suggestion_tyname_ty_dropped_specifier::AAA' declared here}}
+namespace N { }
+using typename N::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_tyname_ty_dropped_specifier::N'; did you mean '::using_suggestion_tyname_ty_dropped_specifier::AAA'?}}
+}
+
+namespace using_suggestion_val_dropped_specifier {
+void FFF() {} // expected-note {{'::using_suggestion_val_dropped_specifier::FFF' declared here}}
+namespace N { }
+using N::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_specifier::N'; did you mean '::using_suggestion_val_dropped_specifier::FFF'?}}
+}
+
+namespace using_suggestion_member_ty {
+class CCC { public: typedef int AAA; }; // expected-note {{'AAA' declared here}}
+class DDD : public CCC { public: using CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_ty::CCC'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_member_val {
+class CCC { public: void AAA() { } }; // expected-note {{'AAA' declared here}}
+class DDD : public CCC { public: using CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_val::CCC'; did you mean 'AAA'?}}
+}
+
+namespace using_suggestion_member_tyname_ty {
+class CCC { public: typedef int AAA; }; // expected-note {{'AAA' declared here}}
+class DDD : public CCC { public: using typename CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_tyname_ty::CCC'; did you mean 'AAA'?}}
+}
using ::foo::Class1::Function; // expected-error{{incomplete type 'foo::Class1' named in nested name specifier}}
};
}
+
+// Don't suggest non-typenames for positions requiring typenames.
+namespace using_suggestion_tyname_val {
+namespace N { void FFF() {} }
+using typename N::FFG; // expected-error {{no member named 'FFG' in namespace 'using_suggestion_tyname_val::N'}}
+}
+
+namespace using_suggestion_member_tyname_val {
+class CCC { public: void AAA() { } };
+class DDD : public CCC { public: using typename CCC::AAB; }; // expected-error {{no member named 'AAB' in 'using_suggestion_member_tyname_val::CCC'}}
+}
+
+namespace using_suggestion_tyname_val_dropped_specifier {
+void FFF() {}
+namespace N { }
+using typename N::FFG; // expected-error {{no member named 'FFG' in namespace 'using_suggestion_tyname_val_dropped_specifier::N'}}
+}
+
+// Currently hints aren't provided to drop out the incorrect M::.
+namespace using_suggestion_ty_dropped_nested_specifier {
+namespace N {
+class AAA {};
+namespace M { }
+}
+using N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_ty_dropped_nested_specifier::N::M'}}
+}
+
+namespace using_suggestion_tyname_ty_dropped_nested_specifier {
+namespace N {
+class AAA {};
+namespace M { }
+}
+using typename N::M::AAA; // expected-error {{no member named 'AAA' in namespace 'using_suggestion_tyname_ty_dropped_nested_specifier::N::M'}}
+}
+
+namespace using_suggestion_val_dropped_nested_specifier {
+namespace N {
+void FFF() {}
+namespace M { }
+}
+using N::M::FFF; // expected-error {{no member named 'FFF' in namespace 'using_suggestion_val_dropped_nested_specifier::N::M'}}
+}