15 changes: 9 additions & 6 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -218,7 +218,8 @@ ParsedType Sema::getTypeName(const IdentifierInfo &II, SourceLocation NameLoc,
if (CorrectedII) {
TypeNameValidatorCCC Validator(true, isClassName);
TypoCorrection Correction = CorrectTypo(Result.getLookupNameInfo(),
Kind, S, SS, Validator);
Kind, S, SS, Validator,
CTK_ErrorRecovery);
IdentifierInfo *NewII = Correction.getCorrectionAsIdentifierInfo();
TemplateTy Template;
bool MemberOfUnknownSpecialization;
Expand Down Expand Up @@ -408,7 +409,7 @@ bool Sema::DiagnoseUnknownTypeName(IdentifierInfo *&II,
TypeNameValidatorCCC Validator(false, false, AllowClassTemplates);
if (TypoCorrection Corrected = CorrectTypo(DeclarationNameInfo(II, IILoc),
LookupOrdinaryName, S, SS,
Validator)) {
Validator, CTK_ErrorRecovery)) {
if (Corrected.isKeyword()) {
// We corrected to a keyword.
diagnoseTypo(Corrected, PDiag(diag::err_unknown_typename_suggest) << II);
Expand Down Expand Up @@ -650,7 +651,8 @@ Sema::NameClassification Sema::ClassifyName(Scope *S,
SecondTry = true;
if (TypoCorrection Corrected = CorrectTypo(Result.getLookupNameInfo(),
Result.getLookupKind(), S,
&SS, *CCC)) {
&SS, *CCC,
CTK_ErrorRecovery)) {
unsigned UnqualifiedDiag = diag::err_undeclared_var_use_suggest;
unsigned QualifiedDiag = diag::err_no_member_suggest;

Expand Down Expand Up @@ -1422,7 +1424,7 @@ ObjCInterfaceDecl *Sema::getObjCInterfaceDecl(IdentifierInfo *&Id,
DeclFilterCCC<ObjCInterfaceDecl> Validator;
if (TypoCorrection C = CorrectTypo(DeclarationNameInfo(Id, IdLoc),
LookupOrdinaryName, TUScope, NULL,
Validator)) {
Validator, CTK_ErrorRecovery)) {
diagnoseTypo(C, PDiag(diag::err_undef_interface_suggest) << Id);
IDecl = C.getCorrectionDeclAs<ObjCInterfaceDecl>();
Id = IDecl->getIdentifier();
Expand Down Expand Up @@ -6160,7 +6162,7 @@ static NamedDecl *DiagnoseInvalidRedeclaration(
} else if ((Correction = SemaRef.CorrectTypo(
Prev.getLookupNameInfo(), Prev.getLookupKind(), S,
&ExtraArgs.D.getCXXScopeSpec(), Validator,
IsLocalFriend ? 0 : NewDC))) {
Sema::CTK_ErrorRecovery, IsLocalFriend ? 0 : NewDC))) {
// Set up everything for the call to ActOnFunctionDeclarator
ExtraArgs.D.SetIdentifier(Correction.getCorrectionAsIdentifierInfo(),
ExtraArgs.D.getIdentifierLoc());
Expand Down Expand Up @@ -10100,7 +10102,8 @@ NamedDecl *Sema::ImplicitlyDefineFunction(SourceLocation Loc,
TypoCorrection Corrected;
DeclFilterCCC<FunctionDecl> Validator;
if (S && (Corrected = CorrectTypo(DeclarationNameInfo(&II, Loc),
LookupOrdinaryName, S, 0, Validator)))
LookupOrdinaryName, S, 0, Validator,
CTK_NonError)))
diagnoseTypo(Corrected, PDiag(diag::note_function_suggestion),
/*ErrorRecovery*/false);
}
Expand Down
8 changes: 5 additions & 3 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2605,7 +2605,7 @@ Sema::BuildMemInitializer(Decl *ConstructorD,
MemInitializerValidatorCCC Validator(ClassDecl);
if (R.empty() && BaseType.isNull() &&
(Corr = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(), S, &SS,
Validator, ClassDecl))) {
Validator, CTK_ErrorRecovery, ClassDecl))) {
if (FieldDecl *Member = Corr.getCorrectionDeclAs<FieldDecl>()) {
// We have found a non-static data member with a similar
// name to what was typed; complain and initialize that
Expand Down Expand Up @@ -6900,7 +6900,8 @@ static bool TryNamespaceTypoCorrection(Sema &S, LookupResult &R, Scope *Sc,
R.clear();
if (TypoCorrection Corrected = S.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), Sc, &SS,
Validator)) {
Validator,
Sema::CTK_ErrorRecovery)) {
if (DeclContext *DC = S.computeDeclContext(SS, false)) {
std::string CorrectedStr(Corrected.getAsString(S.getLangOpts()));
bool DroppedSpecifier = Corrected.WillReplaceSpecifier() &&
Expand Down Expand Up @@ -7471,7 +7472,8 @@ NamedDecl *Sema::BuildUsingDeclaration(Scope *S, AccessSpecifier AS,
UsingValidatorCCC CCC(HasTypenameKeyword, IsInstantiation,
CurContext->isRecord());
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), S, &SS, CCC)){
R.getLookupKind(), S, &SS, CCC,
CTK_ErrorRecovery)){
// We reject any correction for which ND would be NULL.
NamedDecl *ND = Corrected.getCorrectionDecl();
R.setLookupName(Corrected.getCorrection());
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/Sema/SemaDeclObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,7 @@ ActOnStartClassInterface(SourceLocation AtInterfaceLoc,
ObjCInterfaceValidatorCCC Validator(IDecl);
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(SuperName, SuperLoc), LookupOrdinaryName, TUScope,
NULL, Validator)) {
NULL, Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected, PDiag(diag::err_undef_superclass_suggest)
<< SuperName << ClassName);
PrevDecl = Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>();
Expand Down Expand Up @@ -794,7 +794,7 @@ Sema::FindProtocolDeclaration(bool WarnOnDeclarations,
DeclFilterCCC<ObjCProtocolDecl> Validator;
TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(ProtocolId[i].first, ProtocolId[i].second),
LookupObjCProtocolName, TUScope, NULL, Validator);
LookupObjCProtocolName, TUScope, NULL, Validator, CTK_ErrorRecovery);
if ((PDecl = Corrected.getCorrectionDeclAs<ObjCProtocolDecl>()))
diagnoseTypo(Corrected, PDiag(diag::err_undeclared_protocol_suggest)
<< ProtocolId[i].first);
Expand Down Expand Up @@ -1034,7 +1034,8 @@ Decl *Sema::ActOnStartClassImplementation(
ObjCInterfaceValidatorCCC Validator;
TypoCorrection Corrected =
CorrectTypo(DeclarationNameInfo(ClassName, ClassLoc),
LookupOrdinaryName, TUScope, NULL, Validator);
LookupOrdinaryName, TUScope, NULL, Validator,
CTK_NonError);
if (Corrected.getCorrectionDeclAs<ObjCInterfaceDecl>()) {
// Suggest the (potentially) correct interface name. Don't provide a
// code-modification hint or use the typo name for recovery, because
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1843,7 +1843,7 @@ bool Sema::DiagnoseEmptyLookup(Scope *S, CXXScopeSpec &SS, LookupResult &R,
// We didn't find anything, so try to correct for a typo.
TypoCorrection Corrected;
if (S && (Corrected = CorrectTypo(R.getLookupNameInfo(), R.getLookupKind(),
S, &SS, CCC))) {
S, &SS, CCC, CTK_ErrorRecovery))) {
std::string CorrectedStr(Corrected.getAsString(getLangOpts()));
bool DroppedSpecifier =
Corrected.WillReplaceSpecifier() && Name.getAsString() == CorrectedStr;
Expand Down Expand Up @@ -4004,7 +4004,8 @@ static TypoCorrection TryTypoCorrectionForCall(Sema &S, Expr *Fn,

if (TypoCorrection Corrected = S.CorrectTypo(
DeclarationNameInfo(FuncName, NameLoc), Sema::LookupOrdinaryName,
S.getScopeForContext(S.CurContext), NULL, CCC)) {
S.getScopeForContext(S.CurContext), NULL, CCC,
Sema::CTK_ErrorRecovery)) {
if (NamedDecl *ND = Corrected.getCorrectionDecl()) {
if (Corrected.isOverloaded()) {
OverloadCandidateSet OCS(NameLoc, OverloadCandidateSet::CSK_Normal);
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaExprMember.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -627,7 +627,8 @@ LookupMemberExprInRecord(Sema &SemaRef, LookupResult &R,
RecordMemberExprValidatorCCC Validator(RTy);
TypoCorrection Corrected = SemaRef.CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), NULL,
&SS, Validator, DC);
&SS, Validator,
Sema::CTK_ErrorRecovery, DC);
R.clear();
if (Corrected.isResolved() && !Corrected.isKeyword()) {
R.setLookupName(Corrected.getCorrection());
Expand Down Expand Up @@ -1270,7 +1271,8 @@ Sema::LookupMemberExpr(LookupResult &R, ExprResult &BaseExpr,
Validator.IsObjCIvarLookup = IsArrow;
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
LookupMemberName, NULL, NULL,
Validator, IDecl)) {
Validator, CTK_ErrorRecovery,
IDecl)) {
IV = Corrected.getCorrectionDeclAs<ObjCIvarDecl>();
diagnoseTypo(Corrected,
PDiag(diag::err_typecheck_member_reference_ivar_suggest)
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Sema/SemaExprObjC.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1669,7 +1669,7 @@ HandleExprPropertyRefExpr(const ObjCObjectPointerType *OPT,
DeclFilterCCC<ObjCPropertyDecl> Validator;
if (TypoCorrection Corrected = CorrectTypo(
DeclarationNameInfo(MemberName, MemberLoc), LookupOrdinaryName, NULL,
NULL, Validator, IFace, false, OPT)) {
NULL, Validator, CTK_ErrorRecovery, IFace, false, OPT)) {
diagnoseTypo(Corrected, PDiag(diag::err_property_not_found_suggest)
<< MemberName << QualType(OPT, 0));
DeclarationName TypoResult = Corrected.getCorrection();
Expand Down Expand Up @@ -1901,7 +1901,8 @@ Sema::ObjCMessageKind Sema::getObjCMessageKind(Scope *S,
ObjCInterfaceOrSuperCCC Validator(getCurMethodDecl());
if (TypoCorrection Corrected =
CorrectTypo(Result.getLookupNameInfo(), Result.getLookupKind(), S,
NULL, Validator, NULL, false, NULL, false)) {
NULL, Validator, CTK_ErrorRecovery, NULL, false, NULL,
false)) {
if (Corrected.isKeyword()) {
// If we've found the keyword "super" (the only keyword that would be
// returned by CorrectTypo), this is a send to super.
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaInit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1816,7 +1816,7 @@ InitListChecker::CheckDesignatedInitializer(const InitializedEntity &Entity,
if (TypoCorrection Corrected = SemaRef.CorrectTypo(
DeclarationNameInfo(FieldName, D->getFieldLoc()),
Sema::LookupMemberName, /*Scope=*/ 0, /*SS=*/ 0, Validator,
RT->getDecl())) {
Sema::CTK_ErrorRecovery, RT->getDecl())) {
SemaRef.diagnoseTypo(
Corrected,
SemaRef.PDiag(diag::err_field_designator_unknown_suggest)
Expand Down
36 changes: 34 additions & 2 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include "clang/AST/ExprCXX.h"
#include "clang/Basic/Builtins.h"
#include "clang/Basic/LangOptions.h"
#include "clang/Lex/HeaderSearch.h"
#include "clang/Lex/ModuleLoader.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Sema/DeclSpec.h"
#include "clang/Sema/ExternalSemaSource.h"
#include "clang/Sema/Overload.h"
Expand All @@ -32,6 +35,8 @@
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TypoCorrection.h"
#include "clang/Serialization/GlobalModuleIndex.h"
#include "clang/Serialization/Module.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
Expand Down Expand Up @@ -3924,6 +3929,7 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
Sema::LookupNameKind LookupKind,
Scope *S, CXXScopeSpec *SS,
CorrectionCandidateCallback &CCC,
CorrectTypoKind Mode,
DeclContext *MemberContext,
bool EnteringContext,
const ObjCObjectPointerType *OPT,
Expand Down Expand Up @@ -3978,10 +3984,36 @@ TypoCorrection Sema::CorrectTypo(const DeclarationNameInfo &TypoName,
if (getLangOpts().AltiVec && Typo->isStr("vector"))
return TypoCorrection();

NamespaceSpecifierSet Namespaces(Context, CurContext, SS);

TypoCorrectionConsumer Consumer(*this, Typo);

// Get the module loader (usually compiler instance).
ModuleLoader &Loader = PP.getModuleLoader();

// Look for the symbol in non-imported modules, but only if an error
// actually occurred.
if ((Mode == CTK_ErrorRecovery) && !Loader.buildingModule() &&
getLangOpts().Modules && getLangOpts().ModulesSearchAll) {
// Load global module index, or retrieve a previously loaded one.
GlobalModuleIndex *GlobalIndex = Loader.loadGlobalModuleIndex(
TypoName.getLocStart());

// Only if we have a global index.
if (GlobalIndex) {
GlobalModuleIndex::HitSet FoundModules;

// Find the modules that reference the identifier.
// Note that this only finds top-level modules.
// We'll let diagnoseTypo find the actual declaration module.
if (GlobalIndex->lookupIdentifier(Typo->getName(), FoundModules)) {
TypoCorrection TC(TypoName.getName(), (NestedNameSpecifier *)0, 0);
TC.setCorrectionRange(SS, TypoName);
TC.setRequiresImport(true);
}
}
}

NamespaceSpecifierSet Namespaces(Context, CurContext, SS);

// If a callback object considers an empty typo correction candidate to be
// viable, assume it does not do any actual validation of the candidates.
TypoCorrection EmptyCorrection;
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ ExprResult Sema::ActOnOpenMPIdExpression(Scope *CurScope,
if (!Lookup.isSingleResult()) {
VarDeclFilterCCC Validator(*this);
if (TypoCorrection Corrected = CorrectTypo(Id, LookupOrdinaryName, CurScope,
0, Validator)) {
0, Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(Lookup.empty()? diag::err_undeclared_var_use_suggest
: diag::err_omp_expected_var_arg_suggest)
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ void Sema::LookupTemplateName(LookupResult &Found,
FilterCCC.WantCXXNamedCasts = true;
if (TypoCorrection Corrected = CorrectTypo(Found.getLookupNameInfo(),
Found.getLookupKind(), S, &SS,
FilterCCC, LookupCtx)) {
FilterCCC, CTK_ErrorRecovery,
LookupCtx)) {
Found.setLookupName(Corrected.getCorrection());
if (Corrected.getCorrectionDecl())
Found.addDecl(Corrected.getCorrectionDecl());
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/SemaTemplateVariadic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -810,7 +810,7 @@ ExprResult Sema::ActOnSizeofParameterPackExpr(Scope *S,
case LookupResult::NotFoundInCurrentInstantiation:
if (TypoCorrection Corrected = CorrectTypo(R.getLookupNameInfo(),
R.getLookupKind(), S, 0,
Validator)) {
Validator, CTK_ErrorRecovery)) {
diagnoseTypo(Corrected,
PDiag(diag::err_sizeof_pack_no_pack_name_suggest) << &Name,
PDiag(diag::note_parameter_pack_here));
Expand Down
9 changes: 9 additions & 0 deletions clang/test/Modules/Inputs/undefined-type-fixit/module.map
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module public1 {
header "public1.h"
}
module public2 {
header "public2.h"
module public2sub {
header "public2sub.h"
}
}
6 changes: 6 additions & 0 deletions clang/test/Modules/Inputs/undefined-type-fixit/public1.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef PUBLIC1_H
#define PUBLIC1_H

struct use_this1 { int field; };

#endif
6 changes: 6 additions & 0 deletions clang/test/Modules/Inputs/undefined-type-fixit/public2.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef PUBLIC2_H
#define PUBLIC2_H

struct use_this2 { int field; };

#endif
6 changes: 6 additions & 0 deletions clang/test/Modules/Inputs/undefined-type-fixit/public2sub.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#ifndef PUBLIC2SUB_H
#define PUBLIC2SUB_H

struct use_this2sub { int field; };

#endif
12 changes: 12 additions & 0 deletions clang/test/Modules/undefined-type-fixit1.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules-cache-path=%t -fmodules -fmodules-search-all -I %S/Inputs/undefined-type-fixit %s -verify

//#include "public1.h"
#include "public2.h"
#include "public2sub.h"

use_this1 client_variable1; // expected-error{{declaration of 'use_this1' must be imported from module 'public1' before it is required}}
use_this2 client_variable2;
use_this2sub client_variable2sub;

// expected-note@Inputs/undefined-type-fixit/public1.h:4 {{previous declaration is here}}
3 changes: 3 additions & 0 deletions clang/unittests/Basic/SourceManagerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ class VoidModuleLoader : public ModuleLoader {
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }

virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
{ return 0; }
};

TEST_F(SourceManagerTest, isBeforeInTranslationUnit) {
Expand Down
1 change: 1 addition & 0 deletions clang/unittests/Lex/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,5 @@ target_link_libraries(LexTests
clangLex
clangParse
clangSema
clangSerialization
)
3 changes: 3 additions & 0 deletions clang/unittests/Lex/LexerTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ class VoidModuleLoader : public ModuleLoader {
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }

virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
{ return 0; }
};

// The test fixture.
Expand Down
4 changes: 2 additions & 2 deletions clang/unittests/Lex/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

CLANG_LEVEL = ../..
TESTNAME = Lex
LINK_COMPONENTS := mcparser support mc
LINK_COMPONENTS := mcparser support mc bitreader
USEDLIBS = clangParse.a clangSema.a clangAnalysis.a clangEdit.a \
clangAST.a clangLex.a clangBasic.a
clangSerialization.a clangAST.a clangLex.a clangBasic.a

include $(CLANG_LEVEL)/unittests/Makefile
3 changes: 3 additions & 0 deletions clang/unittests/Lex/PPCallbacksTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class VoidModuleLoader : public ModuleLoader {
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }

virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
{ return 0; }
};

// Stub to collect data from InclusionDirective callbacks.
Expand Down
3 changes: 3 additions & 0 deletions clang/unittests/Lex/PPConditionalDirectiveRecordTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ class VoidModuleLoader : public ModuleLoader {
Module::NameVisibilityKind Visibility,
SourceLocation ImportLoc,
bool Complain) { }

virtual GlobalModuleIndex *loadGlobalModuleIndex(SourceLocation TriggerLoc)
{ return 0; }
};

TEST_F(PPConditionalDirectiveRecordTest, PPRecAPI) {
Expand Down