]> granicus.if.org Git - clang/commitdiff
Add hooks to ExternalSemaSource for after-the-fact diagnosis of
authorKaelyn Uhrain <rikka@google.com>
Mon, 12 Aug 2013 22:11:14 +0000 (22:11 +0000)
committerKaelyn Uhrain <rikka@google.com>
Mon, 12 Aug 2013 22:11:14 +0000 (22:11 +0000)
incomplete types, courtesy of Luke Zarko.

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@188212 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Sema/ExternalSemaSource.h
include/clang/Sema/MultiplexExternalSemaSource.h
lib/Sema/MultiplexExternalSemaSource.cpp
lib/Sema/SemaType.cpp
unittests/Sema/ExternalSemaSourceTest.cpp

index fd32d7f007a7fe6aa1cfba33a8861f793a3dc55a..325abdf8e517e95955f66ee2a13ab2996825afe5 100644 (file)
@@ -14,6 +14,7 @@
 #define LLVM_CLANG_SEMA_EXTERNAL_SEMA_SOURCE_H
 
 #include "clang/AST/ExternalASTSource.h"
+#include "clang/AST/Type.h"
 #include "clang/Sema/TypoCorrection.h"
 #include "clang/Sema/Weak.h"
 #include "llvm/ADT/MapVector.h"
@@ -204,6 +205,20 @@ public:
     return TypoCorrection();
   }
 
+  /// \brief Produces a diagnostic note if the external source contains a
+  /// complete definition for \p T.
+  ///
+  /// \param Loc the location at which a complete type was required but not
+  /// provided
+  ///
+  /// \param T the \c QualType that should have been complete at \p Loc
+  ///
+  /// \return true if a diagnostic was produced, false otherwise.
+  virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc,
+                                                QualType T) {
+    return false;
+  }
+
   // isa/cast/dyn_cast support
   static bool classof(const ExternalASTSource *Source) {
     return Source->SemaSource;
index bb7ba239cac111ba933170c58bd15a8380e54d3c..e9ba479d1255b30d31780a3ebbbd333fe1784871 100644 (file)
@@ -340,6 +340,18 @@ public:
                                      bool EnteringContext,
                                      const ObjCObjectPointerType *OPT);
 
+  /// \brief Produces a diagnostic note if one of the attached sources
+  /// contains a complete definition for \p T. Queries the sources in list
+  /// order until the first one claims that a diagnostic was produced.
+  ///
+  /// \param Loc the location at which a complete type was required but not
+  /// provided
+  ///
+  /// \param T the \c QualType that should have been complete at \p Loc
+  ///
+  /// \return true if a diagnostic was produced, false otherwise.
+  virtual bool MaybeDiagnoseMissingCompleteType(SourceLocation Loc, QualType T);
+
   // isa/cast/dyn_cast support
   static bool classof(const MultiplexExternalSemaSource*) { return true; }
   //static bool classof(const ExternalSemaSource*) { return true; }
index 43bafd3482bc5ca43714845d3102cb4a04234f79..ad7627a457156e021cd969e1b6f69b890dc588f3 100644 (file)
@@ -289,3 +289,12 @@ TypoCorrection MultiplexExternalSemaSource::CorrectTypo(
   }
   return TypoCorrection();
 }
+
+bool MultiplexExternalSemaSource::MaybeDiagnoseMissingCompleteType(
+    SourceLocation Loc, QualType T) {
+  for (size_t I = 0, E = Sources.size(); I < E; ++I) {
+    if (Sources[I]->MaybeDiagnoseMissingCompleteType(Loc, T))
+      return true;
+  }
+  return false;
+}
index 96c6362879c98998c53b14535dae19dad6be5d38..6998827e16292115f7a5364cd2fd317eb76d7a0a 100644 (file)
@@ -5052,6 +5052,11 @@ bool Sema::RequireCompleteTypeImpl(SourceLocation Loc, QualType T,
   if (IFace && !IFace->getDecl()->isInvalidDecl())
     Diag(IFace->getDecl()->getLocation(), diag::note_forward_class);
 
+  // If we have external information that we can use to suggest a fix,
+  // produce a note.
+  if (ExternalSource)
+    ExternalSource->MaybeDiagnoseMissingCompleteType(Loc, T);
+
   return true;
 }
 
index 8aa626c2df12f24fae1249dac5bf4784c7c28c0b..e27d0cd1e397bf1a1bae5c1d82ca9d13920ec157 100644 (file)
@@ -24,6 +24,21 @@ 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.
@@ -211,4 +226,41 @@ TEST(ExternalSemaSource, ExternalTypoCorrectionOrdering) {
   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