[clang-tools-extra] r293909 - [change-namespace] fix unscoped enum constant references.

Eric Liu via cfe-commits cfe-commits at lists.llvm.org
Thu Feb 2 10:59:50 PST 2017


This is breaking build bots, and I am trying to fix it. Feel free to revert
the change if this blocks you.

On Thu, Feb 2, 2017 at 6:51 PM Eric Liu via cfe-commits <
cfe-commits at lists.llvm.org> wrote:

> Author: ioeric
> Date: Thu Feb  2 11:40:38 2017
> New Revision: 293909
>
> URL: http://llvm.org/viewvc/llvm-project?rev=293909&view=rev
> Log:
> [change-namespace] fix unscoped enum constant references.
>
> Reviewers: bkramer
>
> Subscribers: cfe-commits
>
> Differential Revision: https://reviews.llvm.org/D29460
>
> Modified:
>     clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp
>
> clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp
>
> Modified: clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp?rev=293909&r1=293908&r2=293909&view=diff
>
> ==============================================================================
> --- clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp (original)
> +++ clang-tools-extra/trunk/change-namespace/ChangeNamespace.cpp Thu Feb
> 2 11:40:38 2017
> @@ -282,6 +282,10 @@ bool isDeclVisibleAtLocation(const Sourc
>            isNestedDeclContext(DeclCtx, D->getDeclContext()));
>  }
>
> +AST_MATCHER(EnumDecl, isScoped) {
> +    return Node.isScoped();
> +}
> +
>  } // anonymous namespace
>
>  ChangeNamespaceTool::ChangeNamespaceTool(
> @@ -454,6 +458,17 @@ void ChangeNamespaceTool::registerMatche
>                                   to(GlobalVarMatcher.bind("var_decl")))
>                           .bind("var_ref"),
>                       this);
> +
> +  // Handle unscoped enum constant.
> +  auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
> +      hasParent(namespaceDecl()),
> +      unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
> +                   hasAncestor(namespaceDecl(isAnonymous())))))));
> +  Finder->addMatcher(
> +      declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
> +                  to(UnscopedEnumMatcher.bind("enum_const_decl")))
> +          .bind("enum_const_ref"),
> +      this);
>  }
>
>  void ChangeNamespaceTool::run(
> @@ -518,6 +533,21 @@ void ChangeNamespaceTool::run(
>      assert(Context && "Empty decl context.");
>      fixDeclRefExpr(Result, Context->getDeclContext(),
>                     llvm::cast<NamedDecl>(Var), VarRef);
> +  } else if (const auto *EnumConstRef =
> +                 Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
> +    // Do not rename the reference if it is already scoped by the
> EnumDecl name.
> +    if (EnumConstRef->hasQualifier() &&
> +        EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
> +      return;
> +    const auto *EnumConstDecl =
> +        Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
> +    assert(EnumConstDecl);
> +    const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
> +    assert(Context && "Empty decl context.");
> +    // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE".
> Fix it
> +    // if it turns out to be an issue.
> +    fixDeclRefExpr(Result, Context->getDeclContext(),
> +                   llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
>    } else if (const auto *FuncRef =
>                   Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
>      // If this reference has been processed as a function call, we do not
>
> Modified:
> clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp
> URL:
> http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp?rev=293909&r1=293908&r2=293909&view=diff
>
> ==============================================================================
> ---
> clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp
> (original)
> +++
> clang-tools-extra/trunk/unittests/change-namespace/ChangeNamespaceTests.cpp
> Thu Feb  2 11:40:38 2017
> @@ -1774,6 +1774,207 @@ TEST_F(ChangeNamespaceTest, ShortenNames
>    EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
>  }
>
> +TEST_F(ChangeNamespaceTest, SimpleMoveEnum) {
> +  std::string Code = "namespace na {\n"
> +                     "namespace nb {\n"
> +                     "enum class X { X1, X2 };\n"
> +                     "enum Y { Y1, Y2 };\n"
> +                     "} // namespace nb\n"
> +                     "} // namespace na\n";
> +  std::string Expected = "\n\nnamespace x {\n"
> +                         "namespace y {\n"
> +                         "enum class X { X1, X2 };\n"
> +                         "enum Y { Y1, Y2 };\n"
> +                         "} // namespace y\n"
> +                         "} // namespace x\n";
> +
> +  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
> +}
> +
> +TEST_F(ChangeNamespaceTest, ReferencesToEnums) {
> +  std::string Code = "enum Glob { G1, G2 };\n"
> +                     "namespace na {\n"
> +                     "enum class X { X1 };\n"
> +                     "enum Y { Y1, Y2 };\n"
> +                     "namespace nb {\n"
> +                     "void f() {\n"
> +                     "  Glob g1 = Glob::G1;\n"
> +                     "  Glob g2 = G2;\n"
> +                     "  X x1 = X::X1;\n"
> +                     "  Y y1 = Y::Y1;\n"
> +                     "  Y y2 = Y2;\n"
> +                     "}\n"
> +                     "} // namespace nb\n"
> +                     "} // namespace na\n";
> +  std::string Expected = "enum Glob { G1, G2 };\n"
> +                         "namespace na {\n"
> +                         "enum class X { X1 };\n"
> +                         "enum Y { Y1, Y2 };\n"
> +                         "\n"
> +                         "} // namespace na\n"
> +                         "namespace x {\n"
> +                         "namespace y {\n"
> +                         "void f() {\n"
> +                         "  Glob g1 = Glob::G1;\n"
> +                         "  Glob g2 = G2;\n"
> +                         "  ::na::X x1 = ::na::X::X1;\n"
> +                         "  ::na::Y y1 = ::na::Y::Y1;\n"
> +                         "  ::na::Y y2 = ::na::Y::Y2;\n"
> +                         "}\n"
> +                         "} // namespace y\n"
> +                         "} // namespace x\n";
> +
> +  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
> +}
> +
> +TEST_F(ChangeNamespaceTest, NoRedundantEnumUpdate) {
> +  std::string Code = "namespace ns {\n"
> +                     "enum class X { X1 };\n"
> +                     "enum Y { Y1, Y2 };\n"
> +                     "} // namespace ns\n"
> +                     "namespace na {\n"
> +                     "namespace nb {\n"
> +                     "void f() {\n"
> +                     "  ns::X x1 = ns::X::X1;\n"
> +                     "  ns::Y y1 = ns::Y::Y1;\n"
> +                     "  ns::Y y2 = ns::Y2;\n"
> +                     "}\n"
> +                     "} // namespace nb\n"
> +                     "} // namespace na\n";
> +  std::string Expected = "namespace ns {\n"
> +                         "enum class X { X1 };\n"
> +                         "enum Y { Y1, Y2 };\n"
> +                         "} // namespace ns\n"
> +                         "\n"
> +                         "namespace x {\n"
> +                         "namespace y {\n"
> +                         "void f() {\n"
> +                         "  ns::X x1 = ns::X::X1;\n"
> +                         "  ns::Y y1 = ns::Y::Y1;\n"
> +                         // FIXME: this is redundant
> +                         "  ns::Y y2 = ::ns::Y::Y2;\n"
> +                         "}\n"
> +                         "} // namespace y\n"
> +                         "} // namespace x\n";
> +  ;
> +
> +  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
> +}
> +
> +TEST_F(ChangeNamespaceTest, EnumsAndUsingShadows) {
> +  std::string Code = "namespace ns {\n"
> +                     "enum class X { X1 };\n"
> +                     "enum Y { Y1, Y2, Y3 };\n"
> +                     "} // namespace ns\n"
> +                     "using ns::X;\n"
> +                     "using ns::Y;\n"
> +                     "using ns::Y::Y2;\n"
> +                     "using ns::Y::Y3;\n"
> +                     "namespace na {\n"
> +                     "namespace nb {\n"
> +                     "void f() {\n"
> +                     "  X x1 = X::X1;\n"
> +                     "  Y y1 = Y::Y1;\n"
> +                     "  Y y2 = Y2;\n"
> +                     "  Y y3 = Y3;\n"
> +                     "}\n"
> +                     "} // namespace nb\n"
> +                     "} // namespace na\n";
> +  std::string Expected = "namespace ns {\n"
> +                         "enum class X { X1 };\n"
> +                         "enum Y { Y1, Y2, Y3 };\n"
> +                         "} // namespace ns\n"
> +                         "using ns::X;\n"
> +                         "using ns::Y;\n"
> +                         "using ns::Y::Y2;\n"
> +                         "using ns::Y::Y3;\n"
> +                         "\n"
> +                         "namespace x {\n"
> +                         "namespace y {\n"
> +                         "void f() {\n"
> +                         "  X x1 = X::X1;\n"
> +                         "  Y y1 = Y::Y1;\n"
> +                         "  Y y2 = Y2;\n"
> +                         "  Y y3 = Y3;\n"
> +                         "}\n"
> +                         "} // namespace y\n"
> +                         "} // namespace x\n";
> +
> +  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
> +}
> +
> +TEST_F(ChangeNamespaceTest, EnumsAndAliases) {
> +  std::string Code = "namespace ns {\n"
> +                     "enum class X { X1 };\n"
> +                     "enum Y { Y1, Y2, Y3 };\n"
> +                     "} // namespace ns\n"
> +                     "typedef ns::X TX;\n"
> +                     "typedef ns::Y TY;\n"
> +                     "using UX = ns::X;\n"
> +                     "using UY = ns::Y;\n"
> +                     "namespace na {\n"
> +                     "namespace nb {\n"
> +                     "void f() {\n"
> +                     "  ns::X x1 = ns::X::X1;\n"
> +                     "  TX tx1 = TX::X1;\n"
> +                     "  UX ux1 = UX::X1;\n"
> +                     "  ns::Y y1 = ns::Y::Y1;\n"
> +                     "  TY ty1 = TY::Y1;\n"
> +                     "  UY uy1 = UY::Y1;\n"
> +                     "}\n"
> +                     "} // namespace nb\n"
> +                     "} // namespace na\n";
> +  std::string Expected = "namespace ns {\n"
> +                         "enum class X { X1 };\n"
> +                         "enum Y { Y1, Y2, Y3 };\n"
> +                         "} // namespace ns\n"
> +                         "typedef ns::X TX;\n"
> +                         "typedef ns::Y TY;\n"
> +                         "using UX = ns::X;\n"
> +                         "using UY = ns::Y;\n"
> +                         "\n"
> +                         "namespace x {\n"
> +                         "namespace y {\n"
> +                         "void f() {\n"
> +                         "  ns::X x1 = ns::X::X1;\n"
> +                         "  TX tx1 = TX::X1;\n"
> +                         "  UX ux1 = UX::X1;\n"
> +                         "  ns::Y y1 = ns::Y::Y1;\n"
> +                         "  TY ty1 = TY::Y1;\n"
> +                         "  UY uy1 = UY::Y1;\n"
> +                         "}\n"
> +                         "} // namespace y\n"
> +                         "} // namespace x\n";
> +
> +  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
> +}
> +
> +TEST_F(ChangeNamespaceTest, EnumInClass) {
> +  std::string Code = "namespace na {\n"
> +                     "struct X { enum E { E1 }; };\n"
> +                     "namespace nb {\n"
> +                     "void f() {\n"
> +                     "  X::E e = X::E1;\n"
> +                     "  X::E ee = X::E::E1;\n"
> +                     "}\n"
> +                     "} // namespace nb\n"
> +                     "} // namespace na\n";
> +  std::string Expected = "namespace na {\n"
> +                         "struct X { enum E { E1 }; };\n"
> +                         "\n"
> +                         "} // namespace na\n"
> +                         "namespace x {\n"
> +                         "namespace y {\n"
> +                         "void f() {\n"
> +                         "  ::na::X::E e = ::na::X::E1;\n"
> +                         "  ::na::X::E ee = ::na::X::E::E1;\n"
> +                         "}\n"
> +                         "} // namespace y\n"
> +                         "} // namespace x\n";
> +
> +  EXPECT_EQ(format(Expected), runChangeNamespaceOnCode(Code));
> +}
> +
>  } // anonymous namespace
>  } // namespace change_namespace
>  } // namespace clang
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20170202/07eb404c/attachment-0001.html>


More information about the cfe-commits mailing list