r270039 - [Sema] Allow an external sema source to handle delayed typo corrections.
Benjamin Kramer via cfe-commits
cfe-commits at lists.llvm.org
Thu May 19 03:52:27 PDT 2016
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) {
More information about the cfe-commits
mailing list