sammccall created this revision.
sammccall added a reviewer: ilya-biryukov.
Herald added subscribers: cfe-commits, kadircet, arphaman, jkorous, MaskRay.
Herald added a project: clang.

Lifted the helper for spelling one scope from another from
SemaCodeComplete -> AST, to reuse it. It should be useful in other contexts too.


Repository:
  rC Clang

https://reviews.llvm.org/D63085

Files:
  include/clang/AST/DeclBase.h
  lib/AST/DeclBase.cpp
  lib/Sema/SemaCodeComplete.cpp
  lib/Sema/SemaLookup.cpp
  lib/Sema/SemaStmt.cpp
  test/FixIt/fixit-enum.cpp

Index: test/FixIt/fixit-enum.cpp
===================================================================
--- /dev/null
+++ test/FixIt/fixit-enum.cpp
@@ -0,0 +1,19 @@
+// RUN: cp %s %t.cpp
+// RUN: not %clang_cc1 -fixit %t.cpp -Werror
+// RUN: %clang_cc1 %t.cpp -Werror
+
+namespace ns {
+inline namespace q { namespace { enum { A, B, C }; } }
+} // namespace ns
+
+namespace ns2 {
+enum class F { X, Y, Z };
+
+void test(F f, decltype(ns::A) g) {
+  switch (f) {}
+  // CHECK: YYY
+
+  switch (g) {}
+  // CHECK: ZZZ
+}
+} // namespace ns2
Index: lib/Sema/SemaStmt.cpp
===================================================================
--- lib/Sema/SemaStmt.cpp
+++ lib/Sema/SemaStmt.cpp
@@ -1193,14 +1193,31 @@
 
       // Produce a nice diagnostic if multiple values aren't handled.
       if (!UnhandledNames.empty()) {
-        DiagnosticBuilder DB = Diag(CondExpr->getExprLoc(),
-                                    TheDefaultStmt ? diag::warn_def_missing_case
-                                                   : diag::warn_missing_case)
-                               << (int)UnhandledNames.size();
+        DiagnosticBuilder DB =
+            Diag(CondExpr->getExprLoc(), TheDefaultStmt
+                                             ? diag::warn_def_missing_case
+                                             : diag::warn_missing_case)
+            << (int)UnhandledNames.size();
 
         for (size_t I = 0, E = std::min(UnhandledNames.size(), (size_t)3);
              I != E; ++I)
           DB << UnhandledNames[I];
+
+        std::string NewCases;
+        llvm::raw_string_ostream NewCasesOS(NewCases);
+        // Include \n to separate new cases added if there are many.
+        // This suppresses printing the (long) insert text.
+        char Sep = UnhandledNames.size() > 3 ? '\n' : ' ';
+        const NestedNameSpecifier *Qual =
+            CurContext->getQualifierFor(ED->isScoped() ? ED : ED->getParent());
+        for (const auto& Name : UnhandledNames) {
+          NewCasesOS << "case ";
+          if (Qual)
+            Qual->print(NewCasesOS, Context.getPrintingPolicy());
+          NewCasesOS << Name << ':' << Sep;
+        }
+        NewCasesOS << "break;";
+        DB << FixItHint::CreateInsertion(SS->getEndLoc(), NewCasesOS.str());
       }
 
       if (!hasCasesNotInSwitch)
Index: lib/Sema/SemaLookup.cpp
===================================================================
--- lib/Sema/SemaLookup.cpp
+++ lib/Sema/SemaLookup.cpp
@@ -20,6 +20,7 @@
 #include "clang/AST/DeclTemplate.h"
 #include "clang/AST/Expr.h"
 #include "clang/AST/ExprCXX.h"
+#include "clang/AST/NestedNameSpecifier.h"
 #include "clang/Basic/Builtins.h"
 #include "clang/Basic/LangOptions.h"
 #include "clang/Lex/HeaderSearch.h"
Index: lib/Sema/SemaCodeComplete.cpp
===================================================================
--- lib/Sema/SemaCodeComplete.cpp
+++ lib/Sema/SemaCodeComplete.cpp
@@ -648,50 +648,6 @@
   return iterator(DeclOrVector.get<DeclIndexPairVector *>()->end());
 }
 
-/// Compute the qualification required to get from the current context
-/// (\p CurContext) to the target context (\p TargetContext).
-///
-/// \param Context the AST context in which the qualification will be used.
-///
-/// \param CurContext the context where an entity is being named, which is
-/// typically based on the current scope.
-///
-/// \param TargetContext the context in which the named entity actually
-/// resides.
-///
-/// \returns a nested name specifier that refers into the target context, or
-/// NULL if no qualification is needed.
-static NestedNameSpecifier *
-getRequiredQualification(ASTContext &Context, const DeclContext *CurContext,
-                         const DeclContext *TargetContext) {
-  SmallVector<const DeclContext *, 4> TargetParents;
-
-  for (const DeclContext *CommonAncestor = TargetContext;
-       CommonAncestor && !CommonAncestor->Encloses(CurContext);
-       CommonAncestor = CommonAncestor->getLookupParent()) {
-    if (CommonAncestor->isTransparentContext() ||
-        CommonAncestor->isFunctionOrMethod())
-      continue;
-
-    TargetParents.push_back(CommonAncestor);
-  }
-
-  NestedNameSpecifier *Result = nullptr;
-  while (!TargetParents.empty()) {
-    const DeclContext *Parent = TargetParents.pop_back_val();
-
-    if (const auto *Namespace = dyn_cast<NamespaceDecl>(Parent)) {
-      if (!Namespace->getIdentifier())
-        continue;
-
-      Result = NestedNameSpecifier::Create(Context, Result, Namespace);
-    } else if (const auto *TD = dyn_cast<TagDecl>(Parent))
-      Result = NestedNameSpecifier::Create(
-          Context, Result, false, Context.getTypeDeclType(TD).getTypePtr());
-  }
-  return Result;
-}
-
 /// Determine whether \p Id is a name reserved for the implementation (C99
 /// 7.1.3, C++ [lib.global.names]).
 static bool isReservedName(const IdentifierInfo *Id,
@@ -801,8 +757,7 @@
   R.QualifierIsInformative = false;
 
   if (!R.Qualifier)
-    R.Qualifier = getRequiredQualification(SemaRef.Context, CurContext,
-                                           R.Declaration->getDeclContext());
+    R.Qualifier = CurContext->getQualifierFor(R.Declaration->getDeclContext());
   return false;
 }
 
@@ -3970,8 +3925,8 @@
 
     // If we need a nested-name-specifier, add one now.
     if (!InContext) {
-      NestedNameSpecifier *NNS = getRequiredQualification(
-          S.Context, CurContext, Overridden->getDeclContext());
+      NestedNameSpecifier *NNS =
+          CurContext->getQualifierFor(Overridden->getDeclContext());
       if (NNS) {
         std::string Str;
         llvm::raw_string_ostream OS(Str);
@@ -4241,7 +4196,7 @@
     // If there are no prior enumerators in C++, check whether we have to
     // qualify the names of the enumerators that we suggest, because they
     // may not be visible in this scope.
-    Qualifier = getRequiredQualification(Context, CurContext, Enum);
+    Qualifier = CurContext->getQualifierFor(Enum);
   }
 
   Results.EnterNewScope();
Index: lib/AST/DeclBase.cpp
===================================================================
--- lib/AST/DeclBase.cpp
+++ lib/AST/DeclBase.cpp
@@ -1770,6 +1770,38 @@
   return OutermostRD;
 }
 
+NestedNameSpecifier *
+DeclContext::getQualifierFor(const DeclContext *Target) const {
+  SmallVector<const DeclContext *, 4> TargetParents;
+
+  for (const DeclContext *CommonAncestor = Target;
+       CommonAncestor && !CommonAncestor->Encloses(this);
+       CommonAncestor = CommonAncestor->getLookupParent()) {
+    if (CommonAncestor->isTransparentContext() ||
+        CommonAncestor->isFunctionOrMethod())
+      continue;
+
+    TargetParents.push_back(CommonAncestor);
+  }
+
+  NestedNameSpecifier *Result = nullptr;
+  while (!TargetParents.empty()) {
+    const DeclContext *Parent = TargetParents.pop_back_val();
+
+    if (const auto *Namespace = dyn_cast<NamespaceDecl>(Parent)) {
+      if (Namespace->isAnonymousNamespace() || Namespace->isInline())
+        continue;
+
+      Result =
+          NestedNameSpecifier::Create(getParentASTContext(), Result, Namespace);
+    } else if (const auto *TD = dyn_cast<TagDecl>(Parent))
+      Result = NestedNameSpecifier::Create(
+          getParentASTContext(), Result, false,
+          getParentASTContext().getTypeDeclType(TD).getTypePtr());
+  }
+  return Result;
+}
+
 bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const {
   // For non-file contexts, this is equivalent to Equals.
   if (!isFileContext())
Index: include/clang/AST/DeclBase.h
===================================================================
--- include/clang/AST/DeclBase.h
+++ include/clang/AST/DeclBase.h
@@ -52,6 +52,7 @@
 class LinkageSpecDecl;
 class Module;
 class NamedDecl;
+class NestedNameSpecifier;
 class ObjCCategoryDecl;
 class ObjCCategoryImplDecl;
 class ObjCContainerDecl;
@@ -1938,6 +1939,13 @@
     return const_cast<DeclContext *>(this)->getOuterLexicalRecordContext();
   }
 
+  /// Compute the qualification required to get from the current context to
+  /// the target context. Useful for suggesting spellings (e.g. in FixItHints).
+  ///
+  /// \returns a nested name specifier that refers into the target context, or
+  /// nullptr if no qualification is needed or possible.
+  NestedNameSpecifier *getQualifierFor(const DeclContext *Target) const;
+
   /// Test if this context is part of the enclosing namespace set of
   /// the context NS, as defined in C++0x [namespace.def]p9. If either context
   /// isn't a namespace, this is equivalent to Equals().
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to