================ @@ -0,0 +1,222 @@ +//===--- ScopifyEnum.cpp --------------------------------------- -*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "ParsedAST.h" +#include "XRefs.h" +#include "refactor/Tweak.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/SourceManager.h" +#include "clang/Tooling/Core/Replacement.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Error.h" + +#include <functional> + +namespace clang::clangd { +namespace { + +/// Turns an unscoped into a scoped enum type. +/// Before: +/// enum E { EV1, EV2 }; +/// ^ +/// void f() { E e1 = EV1; } +/// +/// After: +/// enum class E { EV1, EV2 }; +/// void f() { E e1 = E::EV1; } +/// +/// Note that the respective project code might not compile anymore +/// if it made use of the now-gone implicit conversion to int. +/// This is out of scope for this tweak. +/// +/// TODO: In the above example, we could detect that the values +/// start with the enum name, and remove that prefix. + +class ScopifyEnum : public Tweak { + const char *id() const final; + std::string title() const override { return "Convert to scoped enum"; } + llvm::StringLiteral kind() const override { + return CodeAction::REFACTOR_KIND; + } + bool prepare(const Selection &Inputs) override; + Expected<Tweak::Effect> apply(const Selection &Inputs) override; + + using MakeReplacement = + std::function<tooling::Replacement(StringRef, StringRef, unsigned)>; + llvm::Error addClassKeywordToDeclarations(); + llvm::Error scopifyEnumValues(); + llvm::Error scopifyEnumValue(const EnumConstantDecl &CD, StringRef Prefix); + llvm::Expected<StringRef> getContentForFile(StringRef FilePath); + unsigned getOffsetFromPosition(const Position &Pos, StringRef Content) const; + llvm::Error addReplacementForReference(const ReferencesResult::Reference &Ref, + const MakeReplacement &GetReplacement); + llvm::Error addReplacement(StringRef FilePath, StringRef Content, + const tooling::Replacement &Replacement); + Position getPosition(const Decl &D) const; + + const EnumDecl *D = nullptr; + const Selection *S = nullptr; + SourceManager *SM = nullptr; + llvm::SmallVector<std::unique_ptr<llvm::MemoryBuffer>> ExtraBuffers; + llvm::StringMap<StringRef> ContentPerFile; + Effect E; +}; + +REGISTER_TWEAK(ScopifyEnum) + +bool ScopifyEnum::prepare(const Selection &Inputs) { + if (!Inputs.AST->getLangOpts().CPlusPlus11) + return false; + const SelectionTree::Node *N = Inputs.ASTSelection.commonAncestor(); + if (!N) + return false; + D = N->ASTNode.get<EnumDecl>(); + return D && !D->isScoped() && D->isThisDeclarationADefinition(); +} + +Expected<Tweak::Effect> ScopifyEnum::apply(const Selection &Inputs) { + S = &Inputs; + SM = &S->AST->getSourceManager(); + E.FormatEdits = false; + ContentPerFile.insert(std::make_pair(SM->getFilename(D->getLocation()), + SM->getBufferData(SM->getMainFileID()))); + + if (auto Err = addClassKeywordToDeclarations()) + return Err; + if (auto Err = scopifyEnumValues()) + return Err; + + return E; +} + +llvm::Error ScopifyEnum::addClassKeywordToDeclarations() { + for (const auto &Ref : + findReferences(*S->AST, getPosition(*D), 0, S->Index, false) + .References) { + if (!(Ref.Attributes & ReferencesResult::Declaration)) + continue; + + static const auto MakeReplacement = [](StringRef FilePath, + StringRef Content, unsigned Offset) { + return tooling::Replacement(FilePath, Offset, 0, "class "); + }; + if (auto Err = addReplacementForReference(Ref, MakeReplacement)) + return Err; + } + return llvm::Error::success(); +} + +llvm::Error ScopifyEnum::scopifyEnumValues() { + std::string PrefixToInsert(D->getName().data()); ---------------- ckandeler wrote:
getNameAsString() appears to be deprecated. I did remove the unneeded data(), though. https://github.com/llvm/llvm-project/pull/67645 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits