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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits