Author: d0k Date: Thu May 19 05:46:10 2016 New Revision: 270039 URL: http://llvm.org/viewvc/llvm-project?rev=270039&view=rev Log: [Sema] Allow an external sema source to handle delayed typo corrections.
This probably isn't perfectly perfect but allows correcting function calls again. Modified: cfe/trunk/lib/Sema/SemaLookup.cpp cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp Modified: cfe/trunk/lib/Sema/SemaLookup.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaLookup.cpp?rev=270039&r1=270038&r2=270039&view=diff ============================================================================== --- cfe/trunk/lib/Sema/SemaLookup.cpp (original) +++ cfe/trunk/lib/Sema/SemaLookup.cpp Thu May 19 05:46:10 2016 @@ -4781,11 +4781,19 @@ TypoExpr *Sema::CorrectTypoDelayed( const ObjCObjectPointerType *OPT) { assert(CCC && "CorrectTypoDelayed requires a CorrectionCandidateCallback"); - TypoCorrection Empty; auto Consumer = makeTypoCorrectionConsumer( TypoName, LookupKind, S, SS, std::move(CCC), MemberContext, EnteringContext, OPT, Mode == CTK_ErrorRecovery); + // Give the external sema source a chance to correct the typo. + TypoCorrection ExternalTypo; + if (ExternalSource && Consumer) { + ExternalTypo = ExternalSource->CorrectTypo( + TypoName, LookupKind, S, SS, *CCC, MemberContext, EnteringContext, OPT); + if (ExternalTypo) + Consumer->addCorrection(ExternalTypo); + } + if (!Consumer || Consumer->empty()) return nullptr; @@ -4793,7 +4801,7 @@ TypoExpr *Sema::CorrectTypoDelayed( // is not more that about a third of the length of the typo's identifier. unsigned ED = Consumer->getBestEditDistance(true); IdentifierInfo *Typo = TypoName.getName().getAsIdentifierInfo(); - if (ED > 0 && Typo->getName().size() / ED < 3) + if (!ExternalTypo && ED > 0 && Typo->getName().size() / ED < 3) return nullptr; ExprEvalContexts.back().NumTypos++; Modified: cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp?rev=270039&r1=270038&r2=270039&view=diff ============================================================================== --- cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp (original) +++ cfe/trunk/unittests/Sema/ExternalSemaSourceTest.cpp Thu May 19 05:46:10 2016 @@ -39,19 +39,18 @@ public: bool Result; }; -// \brief Counts the number of err_using_directive_member_suggest diagnostics -// correcting from one namespace to another while still passing all diagnostics -// along a chain of consumers. -class NamespaceDiagnosticWatcher : public clang::DiagnosticConsumer { +/// Counts the number of typo-correcting diagnostics correcting from one name to +/// another while still passing all diagnostics along a chain of consumers. +class DiagnosticWatcher : public clang::DiagnosticConsumer { DiagnosticConsumer *Chained; - std::string FromNS; - std::string ToNS; + std::string FromName; + std::string ToName; public: - NamespaceDiagnosticWatcher(StringRef From, StringRef To) - : Chained(nullptr), FromNS(From), ToNS("'"), SeenCount(0) { - ToNS.append(To); - ToNS.append("'"); + DiagnosticWatcher(StringRef From, StringRef To) + : Chained(nullptr), FromName(From), ToName("'"), SeenCount(0) { + ToName.append(To); + ToName.append("'"); } void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, @@ -61,7 +60,12 @@ public: if (Info.getID() - 1 == diag::err_using_directive_member_suggest) { const IdentifierInfo *Ident = Info.getArgIdentifier(0); const std::string &CorrectedQuotedStr = Info.getArgStdStr(1); - if (Ident->getName() == FromNS && CorrectedQuotedStr == ToNS) + if (Ident->getName() == FromName && CorrectedQuotedStr == ToName) + ++SeenCount; + } else if (Info.getID() == diag::err_no_member_suggest) { + auto Ident = DeclarationName::getFromOpaqueInteger(Info.getRawArg(0)); + const std::string &CorrectedQuotedStr = Info.getArgStdStr(3); + if (Ident.getAsString() == FromName && CorrectedQuotedStr == ToName) ++SeenCount; } } @@ -78,7 +82,7 @@ public: return false; } - NamespaceDiagnosticWatcher *Chain(DiagnosticConsumer *ToChain) { + DiagnosticWatcher *Chain(DiagnosticConsumer *ToChain) { Chained = ToChain; return this; } @@ -130,11 +134,53 @@ public: int CallCount; }; -// \brief Chains together a vector of NamespaceDiagnosticWatchers and +class FunctionTypoProvider : public clang::ExternalSemaSource { + std::string CorrectFrom; + std::string CorrectTo; + Sema *CurrentSema; + +public: + FunctionTypoProvider(StringRef From, StringRef To) + : CorrectFrom(From), CorrectTo(To), CurrentSema(nullptr), CallCount(0) {} + + void InitializeSema(Sema &S) override { CurrentSema = &S; } + + void ForgetSema() override { CurrentSema = nullptr; } + + TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, int LookupKind, + Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, bool EnteringContext, + const ObjCObjectPointerType *OPT) override { + ++CallCount; + if (CurrentSema && Typo.getName().getAsString() == CorrectFrom) { + DeclContext *DestContext = nullptr; + ASTContext &Context = CurrentSema->getASTContext(); + if (SS) + DestContext = CurrentSema->computeDeclContext(*SS, EnteringContext); + if (!DestContext) + DestContext = Context.getTranslationUnitDecl(); + IdentifierInfo *ToIdent = + CurrentSema->getPreprocessor().getIdentifierInfo(CorrectTo); + auto *NewFunction = FunctionDecl::Create( + Context, DestContext, SourceLocation(), SourceLocation(), ToIdent, + Context.getFunctionType(Context.VoidTy, {}, {}), nullptr, SC_Static); + DestContext->addDecl(NewFunction); + TypoCorrection Correction(ToIdent); + Correction.addCorrectionDecl(NewFunction); + return Correction; + } + return TypoCorrection(); + } + + int CallCount; +}; + +// \brief Chains together a vector of DiagnosticWatchers and // adds a vector of ExternalSemaSources to the CompilerInstance before // performing semantic analysis. class ExternalSemaSourceInstaller : public clang::ASTFrontendAction { - std::vector<NamespaceDiagnosticWatcher *> Watchers; + std::vector<DiagnosticWatcher *> Watchers; std::vector<clang::ExternalSemaSource *> Sources; std::unique_ptr<DiagnosticConsumer> OwnedClient; @@ -170,16 +216,14 @@ public: Sources.push_back(Source); } - void PushWatcher(NamespaceDiagnosticWatcher *Watcher) { - Watchers.push_back(Watcher); - } + void PushWatcher(DiagnosticWatcher *Watcher) { Watchers.push_back(Watcher); } }; -// Make sure that the NamespaceDiagnosticWatcher is not miscounting. +// Make sure that the DiagnosticWatcher is not miscounting. TEST(ExternalSemaSource, SanityCheck) { std::unique_ptr<ExternalSemaSourceInstaller> Installer( new ExternalSemaSourceInstaller); - NamespaceDiagnosticWatcher Watcher("AAB", "BBB"); + DiagnosticWatcher Watcher("AAB", "BBB"); Installer->PushWatcher(&Watcher); std::vector<std::string> Args(1, "-std=c++11"); ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs( @@ -193,7 +237,7 @@ TEST(ExternalSemaSource, ExternalTypoCor std::unique_ptr<ExternalSemaSourceInstaller> Installer( new ExternalSemaSourceInstaller); NamespaceTypoProvider Provider("AAB", "BBB"); - NamespaceDiagnosticWatcher Watcher("AAB", "BBB"); + DiagnosticWatcher Watcher("AAB", "BBB"); Installer->PushSource(&Provider); Installer->PushWatcher(&Watcher); std::vector<std::string> Args(1, "-std=c++11"); @@ -211,7 +255,7 @@ TEST(ExternalSemaSource, ExternalTypoCor NamespaceTypoProvider First("XXX", "BBB"); NamespaceTypoProvider Second("AAB", "CCC"); NamespaceTypoProvider Third("AAB", "DDD"); - NamespaceDiagnosticWatcher Watcher("AAB", "CCC"); + DiagnosticWatcher Watcher("AAB", "CCC"); Installer->PushSource(&First); Installer->PushSource(&Second); Installer->PushSource(&Third); @@ -225,6 +269,21 @@ TEST(ExternalSemaSource, ExternalTypoCor ASSERT_EQ(1, Watcher.SeenCount); } +TEST(ExternalSemaSource, ExternalDelayedTypoCorrection) { + std::unique_ptr<ExternalSemaSourceInstaller> Installer( + new ExternalSemaSourceInstaller); + FunctionTypoProvider Provider("aaa", "bbb"); + DiagnosticWatcher Watcher("aaa", "bbb"); + Installer->PushSource(&Provider); + Installer->PushWatcher(&Watcher); + std::vector<std::string> Args(1, "-std=c++11"); + ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs( + Installer.release(), "namespace AAA { } void foo() { AAA::aaa(); }", + Args)); + ASSERT_LE(0, Provider.CallCount); + ASSERT_EQ(1, Watcher.SeenCount); +} + // We should only try MaybeDiagnoseMissingCompleteType if we can't otherwise // solve the problem. TEST(ExternalSemaSource, TryOtherTacticsBeforeDiagnosing) { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits