diff options
author | Benjamin Kramer <benny.kra@googlemail.com> | 2016-05-19 10:46:10 +0000 |
---|---|---|
committer | Benjamin Kramer <benny.kra@googlemail.com> | 2016-05-19 10:46:10 +0000 |
commit | 38d99f6be1ba2f56c118c3ed970018a386de5add (patch) | |
tree | 7938af38d89eca0a1c5c17689e5a56fe51b5ef36 /unittests/Sema | |
parent | 6a15942a75b0e1cf99f738ebc2d7394626881f34 (diff) |
[Sema] Allow an external sema source to handle delayed typo corrections.
This probably isn't perfectly perfect but allows correcting function calls
again.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@270039 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'unittests/Sema')
-rw-r--r-- | unittests/Sema/ExternalSemaSourceTest.cpp | 101 |
1 files changed, 80 insertions, 21 deletions
diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp index 703e97b4ac..d2cdd633fa 100644 --- a/unittests/Sema/ExternalSemaSourceTest.cpp +++ b/unittests/Sema/ExternalSemaSourceTest.cpp @@ -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, ExternalTypoCorrectionPrioritized) { 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, ExternalTypoCorrectionOrdering) { 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, ExternalTypoCorrectionOrdering) { 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) { |