[Frontend] Allow attaching an external sema source to compiler instance and extra diags to TypoCorrections
This can be used to append alternative typo corrections to an existing diag.
include-fixer can use it to suggest includes to be added.
Differential Revision: https://reviews.llvm.org/D26745
llvm-svn: 287128
diff --git a/clang/unittests/Frontend/FrontendActionTest.cpp b/clang/unittests/Frontend/FrontendActionTest.cpp
index 39a131f..c3e6adb 100644
--- a/clang/unittests/Frontend/FrontendActionTest.cpp
+++ b/clang/unittests/Frontend/FrontendActionTest.cpp
@@ -13,6 +13,7 @@
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/CompilerInvocation.h"
#include "clang/Frontend/FrontendAction.h"
+#include "clang/Frontend/FrontendActions.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Sema.h"
@@ -192,4 +193,66 @@
ASSERT_TRUE(TestAction.SeenEnd);
}
+class TypoExternalSemaSource : public ExternalSemaSource {
+ CompilerInstance &CI;
+
+public:
+ TypoExternalSemaSource(CompilerInstance &CI) : CI(CI) {}
+
+ TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, int LookupKind,
+ Scope *S, CXXScopeSpec *SS,
+ CorrectionCandidateCallback &CCC,
+ DeclContext *MemberContext, bool EnteringContext,
+ const ObjCObjectPointerType *OPT) override {
+ // Generate a fake typo correction with one attached note.
+ ASTContext &Ctx = CI.getASTContext();
+ TypoCorrection TC(DeclarationName(&Ctx.Idents.get("moo")));
+ unsigned DiagID = Ctx.getDiagnostics().getCustomDiagID(
+ DiagnosticsEngine::Note, "This is a note");
+ TC.addExtraDiagnostic(PartialDiagnostic(DiagID, Ctx.getDiagAllocator()));
+ return TC;
+ }
+};
+
+struct TypoDiagnosticConsumer : public DiagnosticConsumer {
+ void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel,
+ const Diagnostic &Info) override {
+ // Capture errors and notes. There should be one of each.
+ if (DiagLevel == DiagnosticsEngine::Error) {
+ assert(Error.empty());
+ Info.FormatDiagnostic(Error);
+ } else {
+ assert(Note.empty());
+ Info.FormatDiagnostic(Note);
+ }
+ }
+ SmallString<32> Error;
+ SmallString<32> Note;
+};
+
+TEST(ASTFrontendAction, ExternalSemaSource) {
+ auto *Invocation = new CompilerInvocation;
+ Invocation->getLangOpts()->CPlusPlus = true;
+ Invocation->getPreprocessorOpts().addRemappedFile(
+ "test.cc", MemoryBuffer::getMemBuffer("void fooo();\n"
+ "int main() { foo(); }")
+ .release());
+ Invocation->getFrontendOpts().Inputs.push_back(
+ FrontendInputFile("test.cc", IK_CXX));
+ Invocation->getFrontendOpts().ProgramAction = frontend::ParseSyntaxOnly;
+ Invocation->getTargetOpts().Triple = "i386-unknown-linux-gnu";
+ CompilerInstance Compiler;
+ Compiler.setInvocation(Invocation);
+ auto *TDC = new TypoDiagnosticConsumer;
+ Compiler.createDiagnostics(TDC, /*ShouldOwnClient=*/true);
+ Compiler.setExternalSemaSource(new TypoExternalSemaSource(Compiler));
+
+ SyntaxOnlyAction TestAction;
+ ASSERT_TRUE(Compiler.ExecuteAction(TestAction));
+ // There should be one error correcting to 'moo' and a note attached to it.
+ EXPECT_EQ("use of undeclared identifier 'foo'; did you mean 'moo'?",
+ TDC->Error.str().str());
+ EXPECT_EQ("This is a note", TDC->Note.str().str());
+}
+
} // anonymous namespace