diff options
author | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
---|---|---|
committer | dim <dim@FreeBSD.org> | 2013-12-22 00:07:40 +0000 |
commit | 952eddef9aff85b1e92626e89baaf7a360e2ac85 (patch) | |
tree | df8df0b0067b381eab470a3b8f28d14a552a6340 /unittests/Sema/ExternalSemaSourceTest.cpp | |
parent | ea266cad53e3d49771fa38103913d3ec7a166694 (diff) | |
download | FreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.zip FreeBSD-src-952eddef9aff85b1e92626e89baaf7a360e2ac85.tar.gz |
Vendor import of clang release_34 branch r197841 (effectively, 3.4 RC3):
https://llvm.org/svn/llvm-project/cfe/branches/release_34@197841
Diffstat (limited to 'unittests/Sema/ExternalSemaSourceTest.cpp')
-rw-r--r-- | unittests/Sema/ExternalSemaSourceTest.cpp | 266 |
1 files changed, 266 insertions, 0 deletions
diff --git a/unittests/Sema/ExternalSemaSourceTest.cpp b/unittests/Sema/ExternalSemaSourceTest.cpp new file mode 100644 index 0000000..e27d0cd --- /dev/null +++ b/unittests/Sema/ExternalSemaSourceTest.cpp @@ -0,0 +1,266 @@ +//=== unittests/Sema/ExternalSemaSourceTest.cpp - ExternalSemaSource tests ===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/ASTConsumer.h" +#include "clang/AST/ASTContext.h" +#include "clang/Frontend/CompilerInstance.h" +#include "clang/Lex/Preprocessor.h" +#include "clang/Parse/ParseAST.h" +#include "clang/Sema/ExternalSemaSource.h" +#include "clang/Sema/Sema.h" +#include "clang/Sema/SemaDiagnostic.h" +#include "clang/Sema/TypoCorrection.h" +#include "clang/Tooling/Tooling.h" +#include "gtest/gtest.h" + +using namespace clang; +using namespace clang::tooling; + +namespace { + +// \brief Counts the number of times MaybeDiagnoseMissingCompleteType +// is called. Returns the result it was provided on creation. +class CompleteTypeDiagnoser : public clang::ExternalSemaSource { +public: + CompleteTypeDiagnoser(bool MockResult) : CallCount(0), Result(MockResult) {} + + virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation L, QualType T) { + ++CallCount; + return Result; + } + + int CallCount; + 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 { + DiagnosticConsumer *Chained; + std::string FromNS; + std::string ToNS; + +public: + NamespaceDiagnosticWatcher(StringRef From, StringRef To) + : Chained(NULL), FromNS(From), ToNS("'"), SeenCount(0) { + ToNS.append(To); + ToNS.append("'"); + } + + virtual void HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, + const Diagnostic &Info) { + if (Chained) + Chained->HandleDiagnostic(DiagLevel, Info); + 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) + ++SeenCount; + } + } + + virtual void clear() { + DiagnosticConsumer::clear(); + if (Chained) + Chained->clear(); + } + + virtual bool IncludeInDiagnosticCounts() const { + if (Chained) + return Chained->IncludeInDiagnosticCounts(); + return false; + } + + NamespaceDiagnosticWatcher *Chain(DiagnosticConsumer *ToChain) { + Chained = ToChain; + return this; + } + + int SeenCount; +}; + +// \brief Always corrects a typo matching CorrectFrom with a new namespace +// with the name CorrectTo. +class NamespaceTypoProvider : public clang::ExternalSemaSource { + std::string CorrectFrom; + std::string CorrectTo; + Sema *CurrentSema; + +public: + NamespaceTypoProvider(StringRef From, StringRef To) + : CorrectFrom(From), CorrectTo(To), CurrentSema(NULL), CallCount(0) {} + + virtual void InitializeSema(Sema &S) { CurrentSema = &S; } + + virtual void ForgetSema() { CurrentSema = NULL; } + + virtual TypoCorrection CorrectTypo(const DeclarationNameInfo &Typo, + int LookupKind, Scope *S, CXXScopeSpec *SS, + CorrectionCandidateCallback &CCC, + DeclContext *MemberContext, + bool EnteringContext, + const ObjCObjectPointerType *OPT) { + ++CallCount; + if (CurrentSema && Typo.getName().getAsString() == CorrectFrom) { + DeclContext *DestContext = NULL; + ASTContext &Context = CurrentSema->getASTContext(); + if (SS != NULL) + DestContext = CurrentSema->computeDeclContext(*SS, EnteringContext); + if (DestContext == NULL) + DestContext = Context.getTranslationUnitDecl(); + IdentifierInfo *ToIdent = + CurrentSema->getPreprocessor().getIdentifierInfo(CorrectTo); + NamespaceDecl *NewNamespace = + NamespaceDecl::Create(Context, DestContext, false, Typo.getBeginLoc(), + Typo.getLoc(), ToIdent, NULL); + DestContext->addDecl(NewNamespace); + TypoCorrection Correction(ToIdent); + Correction.addCorrectionDecl(NewNamespace); + return Correction; + } + return TypoCorrection(); + } + + int CallCount; +}; + +// \brief Chains together a vector of NamespaceDiagnosticWatchers and +// adds a vector of ExternalSemaSources to the CompilerInstance before +// performing semantic analysis. +class ExternalSemaSourceInstaller : public clang::ASTFrontendAction { + std::vector<NamespaceDiagnosticWatcher *> Watchers; + std::vector<clang::ExternalSemaSource *> Sources; + llvm::OwningPtr<DiagnosticConsumer> OwnedClient; + +protected: + virtual clang::ASTConsumer * + CreateASTConsumer(clang::CompilerInstance &Compiler, + llvm::StringRef /* dummy */) { + return new clang::ASTConsumer(); + } + + virtual void ExecuteAction() { + CompilerInstance &CI = getCompilerInstance(); + ASSERT_FALSE(CI.hasSema()); + CI.createSema(getTranslationUnitKind(), NULL); + ASSERT_TRUE(CI.hasDiagnostics()); + DiagnosticsEngine &Diagnostics = CI.getDiagnostics(); + DiagnosticConsumer *Client = Diagnostics.getClient(); + if (Diagnostics.ownsClient()) + OwnedClient.reset(Diagnostics.takeClient()); + for (size_t I = 0, E = Watchers.size(); I < E; ++I) + Client = Watchers[I]->Chain(Client); + Diagnostics.setClient(Client, false); + for (size_t I = 0, E = Sources.size(); I < E; ++I) { + Sources[I]->InitializeSema(CI.getSema()); + CI.getSema().addExternalSource(Sources[I]); + } + ParseAST(CI.getSema(), CI.getFrontendOpts().ShowStats, + CI.getFrontendOpts().SkipFunctionBodies); + } + +public: + void PushSource(clang::ExternalSemaSource *Source) { + Sources.push_back(Source); + } + + void PushWatcher(NamespaceDiagnosticWatcher *Watcher) { + Watchers.push_back(Watcher); + } +}; + +// Make sure that the NamespaceDiagnosticWatcher is not miscounting. +TEST(ExternalSemaSource, SanityCheck) { + llvm::OwningPtr<ExternalSemaSourceInstaller> Installer( + new ExternalSemaSourceInstaller); + NamespaceDiagnosticWatcher Watcher("AAB", "BBB"); + Installer->PushWatcher(&Watcher); + std::vector<std::string> Args(1, "-std=c++11"); + ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs( + Installer.take(), "namespace AAA { } using namespace AAB;", Args)); + ASSERT_EQ(0, Watcher.SeenCount); +} + +// Check that when we add a NamespaceTypeProvider, we use that suggestion +// instead of the usual suggestion we would use above. +TEST(ExternalSemaSource, ExternalTypoCorrectionPrioritized) { + llvm::OwningPtr<ExternalSemaSourceInstaller> Installer( + new ExternalSemaSourceInstaller); + NamespaceTypoProvider Provider("AAB", "BBB"); + NamespaceDiagnosticWatcher Watcher("AAB", "BBB"); + Installer->PushSource(&Provider); + Installer->PushWatcher(&Watcher); + std::vector<std::string> Args(1, "-std=c++11"); + ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs( + Installer.take(), "namespace AAA { } using namespace AAB;", Args)); + ASSERT_LE(0, Provider.CallCount); + ASSERT_EQ(1, Watcher.SeenCount); +} + +// Check that we use the first successful TypoCorrection returned from an +// ExternalSemaSource. +TEST(ExternalSemaSource, ExternalTypoCorrectionOrdering) { + llvm::OwningPtr<ExternalSemaSourceInstaller> Installer( + new ExternalSemaSourceInstaller); + NamespaceTypoProvider First("XXX", "BBB"); + NamespaceTypoProvider Second("AAB", "CCC"); + NamespaceTypoProvider Third("AAB", "DDD"); + NamespaceDiagnosticWatcher Watcher("AAB", "CCC"); + Installer->PushSource(&First); + Installer->PushSource(&Second); + Installer->PushSource(&Third); + Installer->PushWatcher(&Watcher); + std::vector<std::string> Args(1, "-std=c++11"); + ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs( + Installer.take(), "namespace AAA { } using namespace AAB;", Args)); + ASSERT_LE(1, First.CallCount); + ASSERT_LE(1, Second.CallCount); + ASSERT_EQ(0, Third.CallCount); + ASSERT_EQ(1, Watcher.SeenCount); +} + +// We should only try MaybeDiagnoseMissingCompleteType if we can't otherwise +// solve the problem. +TEST(ExternalSemaSource, TryOtherTacticsBeforeDiagnosing) { + llvm::OwningPtr<ExternalSemaSourceInstaller> Installer( + new ExternalSemaSourceInstaller); + CompleteTypeDiagnoser Diagnoser(false); + Installer->PushSource(&Diagnoser); + std::vector<std::string> Args(1, "-std=c++11"); + // This code hits the class template specialization/class member of a class + // template specialization checks in Sema::RequireCompleteTypeImpl. + ASSERT_TRUE(clang::tooling::runToolOnCodeWithArgs( + Installer.take(), + "template <typename T> struct S { class C { }; }; S<char>::C SCInst;", + Args)); + ASSERT_EQ(0, Diagnoser.CallCount); +} + +// The first ExternalSemaSource where MaybeDiagnoseMissingCompleteType returns +// true should be the last one called. +TEST(ExternalSemaSource, FirstDiagnoserTaken) { + llvm::OwningPtr<ExternalSemaSourceInstaller> Installer( + new ExternalSemaSourceInstaller); + CompleteTypeDiagnoser First(false); + CompleteTypeDiagnoser Second(true); + CompleteTypeDiagnoser Third(true); + Installer->PushSource(&First); + Installer->PushSource(&Second); + Installer->PushSource(&Third); + std::vector<std::string> Args(1, "-std=c++11"); + ASSERT_FALSE(clang::tooling::runToolOnCodeWithArgs( + Installer.take(), "class Incomplete; Incomplete IncompleteInstance;", + Args)); + ASSERT_EQ(1, First.CallCount); + ASSERT_EQ(1, Second.CallCount); + ASSERT_EQ(0, Third.CallCount); +} + +} // anonymous namespace |