[clang-tools-extra] r363680 - [clangd] Add hidden tweaks to dump AST/selection.
Sam McCall via cfe-commits
cfe-commits at lists.llvm.org
Tue Jun 18 06:37:54 PDT 2019
Author: sammccall
Date: Tue Jun 18 06:37:54 2019
New Revision: 363680
URL: http://llvm.org/viewvc/llvm-project?rev=363680&view=rev
Log:
[clangd] Add hidden tweaks to dump AST/selection.
Summary:
This introduces a few new concepts:
- tweaks have an Intent (they don't all advertise as refactorings)
- tweaks may produce messages (for ShowMessage notification). Generalized
Replacements -> Effect.
- tweaks (and other features) may be hidden (clangd -hidden-features flag).
We may choose to promote these one day. I'm not sure they're worth their own
feature flags though.
Verified it in vim-clangd (not yet open source), curious if the UI is ok in VSCode.
Reviewers: ilya-biryukov
Subscribers: mgorny, MaskRay, jkorous, arphaman, kadircet, cfe-commits
Tags: #clang
Differential Revision: https://reviews.llvm.org/D62538
Added:
clang-tools-extra/trunk/clangd/refactor/tweaks/DumpAST.cpp
Modified:
clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
clang-tools-extra/trunk/clangd/ClangdServer.cpp
clang-tools-extra/trunk/clangd/ClangdServer.h
clang-tools-extra/trunk/clangd/Protocol.cpp
clang-tools-extra/trunk/clangd/Protocol.h
clang-tools-extra/trunk/clangd/Selection.cpp
clang-tools-extra/trunk/clangd/refactor/Tweak.h
clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt
clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp
clang-tools-extra/trunk/clangd/refactor/tweaks/SwapIfBranches.cpp
clang-tools-extra/trunk/clangd/tool/ClangdMain.cpp
clang-tools-extra/trunk/clangd/unittests/SelectionTests.cpp
clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp
Modified: clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdLSPServer.cpp Tue Jun 18 06:37:54 2019
@@ -13,6 +13,7 @@
#include "SourceCode.h"
#include "Trace.h"
#include "URI.h"
+#include "refactor/Tweak.h"
#include "clang/Tooling/Core/Replacement.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/ScopeExit.h"
@@ -31,7 +32,14 @@ CodeAction toCodeAction(const ClangdServ
Range Selection) {
CodeAction CA;
CA.title = T.Title;
- CA.kind = CodeAction::REFACTOR_KIND;
+ switch (T.Intent) {
+ case Tweak::Refactor:
+ CA.kind = CodeAction::REFACTOR_KIND;
+ break;
+ case Tweak::Info:
+ CA.kind = CodeAction::INFO_KIND;
+ break;
+ }
// This tweak may have an expensive second stage, we only run it if the user
// actually chooses it in the UI. We reply with a command that would run the
// corresponding tweak.
@@ -481,18 +489,25 @@ void ClangdLSPServer::onCommand(const Ex
llvm::inconvertibleErrorCode(),
"trying to apply a code action for a non-added file"));
- auto Action = [ApplyEdit](decltype(Reply) Reply, URIForFile File,
- std::string Code,
- llvm::Expected<std::vector<TextEdit>> R) {
+ auto Action = [this, ApplyEdit](decltype(Reply) Reply, URIForFile File,
+ std::string Code,
+ llvm::Expected<Tweak::Effect> R) {
if (!R)
return Reply(R.takeError());
- WorkspaceEdit WE;
- WE.changes.emplace();
- (*WE.changes)[File.uri()] = std::move(*R);
-
- Reply("Fix applied.");
- ApplyEdit(std::move(WE));
+ if (R->ApplyEdit) {
+ WorkspaceEdit WE;
+ WE.changes.emplace();
+ (*WE.changes)[File.uri()] = replacementsToEdits(Code, *R->ApplyEdit);
+ ApplyEdit(std::move(WE));
+ }
+ if (R->ShowMessage) {
+ ShowMessageParams Msg;
+ Msg.message = *R->ShowMessage;
+ Msg.type = MessageType::Info;
+ notify("window/showMessage", Msg);
+ }
+ Reply("Tweak applied.");
};
Server->applyTweak(Params.tweakArgs->file.file(),
Params.tweakArgs->selection, Params.tweakArgs->tweakID,
Modified: clang-tools-extra/trunk/clangd/ClangdServer.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.cpp (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.cpp Tue Jun 18 06:37:54 2019
@@ -95,6 +95,7 @@ ClangdServer::ClangdServer(const GlobalC
: nullptr),
GetClangTidyOptions(Opts.GetClangTidyOptions),
SuggestMissingIncludes(Opts.SuggestMissingIncludes),
+ EnableHiddenFeatures(Opts.HiddenFeatures),
WorkspaceRoot(Opts.WorkspaceRoot),
// Pass a callback into `WorkScheduler` to extract symbols from a newly
// parsed file and rebuild the file index synchronously each time an AST
@@ -303,16 +304,19 @@ tweakSelection(const Range &Sel, const I
void ClangdServer::enumerateTweaks(PathRef File, Range Sel,
Callback<std::vector<TweakRef>> CB) {
- auto Action = [Sel](decltype(CB) CB, std::string File,
- Expected<InputsAndAST> InpAST) {
+ auto Action = [this, Sel](decltype(CB) CB, std::string File,
+ Expected<InputsAndAST> InpAST) {
if (!InpAST)
return CB(InpAST.takeError());
auto Selection = tweakSelection(Sel, *InpAST);
if (!Selection)
return CB(Selection.takeError());
std::vector<TweakRef> Res;
- for (auto &T : prepareTweaks(*Selection))
- Res.push_back({T->id(), T->title()});
+ for (auto &T : prepareTweaks(*Selection)) {
+ if (T->hidden() && !EnableHiddenFeatures)
+ continue;
+ Res.push_back({T->id(), T->title(), T->intent()});
+ }
CB(std::move(Res));
};
@@ -321,7 +325,7 @@ void ClangdServer::enumerateTweaks(PathR
}
void ClangdServer::applyTweak(PathRef File, Range Sel, StringRef TweakID,
- Callback<std::vector<TextEdit>> CB) {
+ Callback<Tweak::Effect> CB) {
auto Action = [Sel](decltype(CB) CB, std::string File, std::string TweakID,
Expected<InputsAndAST> InpAST) {
if (!InpAST)
@@ -332,17 +336,19 @@ void ClangdServer::applyTweak(PathRef Fi
auto A = prepareTweak(TweakID, *Selection);
if (!A)
return CB(A.takeError());
- auto Raw = (*A)->apply(*Selection);
- if (!Raw)
- return CB(Raw.takeError());
- // FIXME: this function has I/O operations (find .clang-format file), figure
- // out a way to cache the format style.
- auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents,
- InpAST->Inputs.FS.get());
- auto Formatted = cleanupAndFormat(InpAST->Inputs.Contents, *Raw, Style);
- if (!Formatted)
- return CB(Formatted.takeError());
- return CB(replacementsToEdits(InpAST->Inputs.Contents, *Formatted));
+ auto Effect = (*A)->apply(*Selection);
+ if (!Effect)
+ return CB(Effect.takeError());
+ if (Effect->ApplyEdit) {
+ // FIXME: this function has I/O operations (find .clang-format file),
+ // figure out a way to cache the format style.
+ auto Style = getFormatStyleForFile(File, InpAST->Inputs.Contents,
+ InpAST->Inputs.FS.get());
+ if (auto Formatted = cleanupAndFormat(InpAST->Inputs.Contents,
+ *Effect->ApplyEdit, Style))
+ Effect->ApplyEdit = std::move(*Formatted);
+ }
+ return CB(std::move(*Effect));
};
WorkScheduler.runWithAST(
"ApplyTweak", File,
Modified: clang-tools-extra/trunk/clangd/ClangdServer.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/ClangdServer.h?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/ClangdServer.h (original)
+++ clang-tools-extra/trunk/clangd/ClangdServer.h Tue Jun 18 06:37:54 2019
@@ -123,6 +123,10 @@ public:
std::chrono::milliseconds(500);
bool SuggestMissingIncludes = false;
+
+ /// Enable hidden features mostly useful to clangd developers.
+ /// e.g. tweaks to dump the AST.
+ bool HiddenFeatures = false;
};
// Sensible default options for use in tests.
// Features like indexing must be enabled if desired.
@@ -227,6 +231,7 @@ public:
struct TweakRef {
std::string ID; /// ID to pass for applyTweak.
std::string Title; /// A single-line message to show in the UI.
+ Tweak::Intent Intent;
};
/// Enumerate the code tweaks available to the user at a specified point.
void enumerateTweaks(PathRef File, Range Sel,
@@ -234,7 +239,7 @@ public:
/// Apply the code tweak with a specified \p ID.
void applyTweak(PathRef File, Range Sel, StringRef ID,
- Callback<std::vector<TextEdit>> CB);
+ Callback<Tweak::Effect> CB);
/// Only for testing purposes.
/// Waits until all requests to worker thread are finished and dumps AST for
@@ -291,6 +296,7 @@ private:
// If this is true, suggest include insertion fixes for diagnostic errors that
// can be caused by missing includes (e.g. member access in incomplete type).
bool SuggestMissingIncludes = false;
+ bool EnableHiddenFeatures = false;
// GUARDED_BY(CachedCompletionFuzzyFindRequestMutex)
llvm::StringMap<llvm::Optional<FuzzyFindRequest>>
Modified: clang-tools-extra/trunk/clangd/Protocol.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.cpp (original)
+++ clang-tools-extra/trunk/clangd/Protocol.cpp Tue Jun 18 06:37:54 2019
@@ -359,6 +359,14 @@ bool fromJSON(const llvm::json::Value &P
return true;
}
+llvm::json::Value toJSON(const MessageType &R) {
+ return static_cast<int64_t>(R);
+}
+
+llvm::json::Value toJSON(const ShowMessageParams &R) {
+ return llvm::json::Object{{"type", R.type}, {"message", R.message}};
+}
+
bool fromJSON(const llvm::json::Value &Params, DidOpenTextDocumentParams &R) {
llvm::json::ObjectMapper O(Params);
return O && O.map("textDocument", R.textDocument);
@@ -593,6 +601,7 @@ llvm::json::Value toJSON(const Command &
const llvm::StringLiteral CodeAction::QUICKFIX_KIND = "quickfix";
const llvm::StringLiteral CodeAction::REFACTOR_KIND = "refactor";
+const llvm::StringLiteral CodeAction::INFO_KIND = "info";
llvm::json::Value toJSON(const CodeAction &CA) {
auto CodeAction = llvm::json::Object{{"title", CA.title}};
Modified: clang-tools-extra/trunk/clangd/Protocol.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Protocol.h?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Protocol.h (original)
+++ clang-tools-extra/trunk/clangd/Protocol.h Tue Jun 18 06:37:54 2019
@@ -483,6 +483,28 @@ struct InitializeParams {
};
bool fromJSON(const llvm::json::Value &, InitializeParams &);
+enum class MessageType {
+ /// An error message.
+ Error = 1,
+ /// A warning message.
+ Warning = 1,
+ /// An information message.
+ Info = 1,
+ /// A log message.
+ Log = 1,
+};
+llvm::json::Value toJSON(const MessageType &);
+
+/// The show message notification is sent from a server to a client to ask the
+/// client to display a particular message in the user interface.
+struct ShowMessageParams {
+ /// The message type.
+ MessageType type = MessageType::Info;
+ /// The actual message.
+ std::string message;
+};
+llvm::json::Value toJSON(const ShowMessageParams &);
+
struct DidOpenTextDocumentParams {
/// The document that was opened.
TextDocumentItem textDocument;
@@ -740,6 +762,7 @@ struct CodeAction {
llvm::Optional<std::string> kind;
const static llvm::StringLiteral QUICKFIX_KIND;
const static llvm::StringLiteral REFACTOR_KIND;
+ const static llvm::StringLiteral INFO_KIND;
/// The diagnostics that this code action resolves.
llvm::Optional<std::vector<Diagnostic>> diagnostics;
Modified: clang-tools-extra/trunk/clangd/Selection.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/Selection.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/Selection.cpp (original)
+++ clang-tools-extra/trunk/clangd/Selection.cpp Tue Jun 18 06:37:54 2019
@@ -53,6 +53,9 @@ public:
bool TraverseDecl(Decl *X) {
if (X && isa<TranslationUnitDecl>(X))
return Base::TraverseDecl(X); // Already pushed by constructor.
+ // Base::TraverseDecl will suppress children, but not this node itself.
+ if (X && X->isImplicit())
+ return true;
return traverseNode(X, [&] { return Base::TraverseDecl(X); });
}
bool TraverseTypeLoc(TypeLoc X) {
Modified: clang-tools-extra/trunk/clangd/refactor/Tweak.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/Tweak.h?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/Tweak.h (original)
+++ clang-tools-extra/trunk/clangd/refactor/Tweak.h Tue Jun 18 06:37:54 2019
@@ -5,9 +5,9 @@
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
-// Tweaks are small refactoring-like actions that run over the AST and produce
-// the set of edits as a result. They are local, i.e. they should take the
-// current editor context, e.g. the cursor position and selection into account.
+// Tweaks are small actions that run over the AST and produce edits, messages
+// etc as a result. They are local, i.e. they should take the current editor
+// context, e.g. the cursor position and selection into account.
// The actions are executed in two stages:
// - Stage 1 should check whether the action is available in a current
// context. It should be cheap and fast to compute as it is executed for all
@@ -47,10 +47,36 @@ public:
ParsedAST &AST;
/// A location of the cursor in the editor.
SourceLocation Cursor;
- // The AST nodes that were selected.
+ /// The AST nodes that were selected.
SelectionTree ASTSelection;
// FIXME: provide a way to get sources and ASTs for other files.
};
+
+ /// Output of a tweak.
+ enum Intent {
+ /// Apply changes that preserve the behavior of the code.
+ Refactor,
+ /// Provide information to the user.
+ Info,
+ };
+ struct Effect {
+ /// A message to be displayed to the user.
+ llvm::Optional<std::string> ShowMessage;
+ /// An edit to apply to the input file.
+ llvm::Optional<tooling::Replacements> ApplyEdit;
+
+ static Effect applyEdit(tooling::Replacements R) {
+ Effect E;
+ E.ApplyEdit = std::move(R);
+ return E;
+ }
+ static Effect showMessage(StringRef S) {
+ Effect E;
+ E.ShowMessage = S;
+ return E;
+ }
+ };
+
virtual ~Tweak() = default;
/// A unique id of the action, it is always equal to the name of the class
/// defining the Tweak. Definition is provided automatically by
@@ -63,13 +89,19 @@ public:
/// should be moved into 'apply'.
/// Returns true iff the action is available and apply() can be called on it.
virtual bool prepare(const Selection &Sel) = 0;
- /// Run the second stage of the action that would produce the actual changes.
+ /// Run the second stage of the action that would produce the actual effect.
/// EXPECTS: prepare() was called and returned true.
- virtual Expected<tooling::Replacements> apply(const Selection &Sel) = 0;
+ virtual Expected<Effect> apply(const Selection &Sel) = 0;
+
/// A one-line title of the action that should be shown to the users in the
/// UI.
/// EXPECTS: prepare() was called and returned true.
virtual std::string title() const = 0;
+ /// Describes what kind of action this is.
+ /// EXPECTS: prepare() was called and returned true.
+ virtual Intent intent() const = 0;
+ /// Is this a 'hidden' tweak, which are off by default.
+ virtual bool hidden() const { return false; }
};
// All tweaks must be registered in the .cpp file next to their definition.
Modified: clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/CMakeLists.txt Tue Jun 18 06:37:54 2019
@@ -12,6 +12,7 @@ set(LLVM_LINK_COMPONENTS
# $<TARGET_OBJECTS:obj.clangDaemonTweaks> to a list of sources, see
# clangd/tool/CMakeLists.txt for an example.
add_clang_library(clangDaemonTweaks OBJECT
+ DumpAST.cpp
RawStringLiteral.cpp
SwapIfBranches.cpp
Added: clang-tools-extra/trunk/clangd/refactor/tweaks/DumpAST.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/DumpAST.cpp?rev=363680&view=auto
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/DumpAST.cpp (added)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/DumpAST.cpp Tue Jun 18 06:37:54 2019
@@ -0,0 +1,139 @@
+//===--- DumpAST.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
+//
+//===----------------------------------------------------------------------===//
+// Defines a few tweaks that expose AST and related information.
+// Some of these are fairly clang-specific and hidden (e.g. textual AST dumps).
+// Others are more generally useful (class layout) and are exposed by default.
+//===----------------------------------------------------------------------===//
+#include "refactor/Tweak.h"
+#include "clang/AST/ASTTypeTraits.h"
+#include "clang/AST/Type.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+
+namespace clang {
+namespace clangd {
+namespace {
+
+/// Dumps the AST of the selected node.
+/// Input:
+/// fcall("foo");
+/// ^^^^^
+/// Message:
+/// CallExpr
+/// |-DeclRefExpr fcall
+/// `-StringLiteral "foo"
+class DumpAST : public Tweak {
+public:
+ const char *id() const override final;
+
+ bool prepare(const Selection &Inputs) override {
+ for (auto N = Inputs.ASTSelection.commonAncestor(); N && !Node;
+ N = N->Parent)
+ if (dumpable(N->ASTNode))
+ Node = N->ASTNode;
+ return Node.hasValue();
+ }
+ Expected<Effect> apply(const Selection &Inputs) override;
+ std::string title() const override {
+ return llvm::formatv("Dump {0} AST", Node->getNodeKind().asStringRef());
+ }
+ Intent intent() const override { return Info; }
+ bool hidden() const override { return true; }
+
+private:
+ static bool dumpable(const ast_type_traits::DynTypedNode &N) {
+ // Sadly not all node types can be dumped, and there's no API to check.
+ // See DynTypedNode::dump().
+ return N.get<Decl>() || N.get<Stmt>() || N.get<Type>();
+ }
+
+ llvm::Optional<ast_type_traits::DynTypedNode> Node;
+};
+REGISTER_TWEAK(DumpAST)
+
+llvm::Expected<Tweak::Effect> DumpAST::apply(const Selection &Inputs) {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ Node->dump(OS, Inputs.AST.getASTContext().getSourceManager());
+ return Effect::showMessage(std::move(OS.str()));
+}
+
+/// Dumps the SelectionTree.
+/// Input:
+/// int fcall(int);
+/// void foo() {
+/// fcall(2 + 2);
+/// ^^^^^
+/// }
+/// Message:
+/// TranslationUnitDecl
+/// FunctionDecl void foo()
+/// CompoundStmt {}
+/// .CallExpr fcall(2 + 2)
+/// ImplicitCastExpr fcall
+/// .DeclRefExpr fcall
+/// BinaryOperator 2 + 2
+/// *IntegerLiteral 2
+class ShowSelectionTree : public Tweak {
+public:
+ const char *id() const override final;
+
+ bool prepare(const Selection &Inputs) override {
+ return Inputs.ASTSelection.root() != nullptr;
+ }
+ Expected<Effect> apply(const Selection &Inputs) override {
+ return Effect::showMessage(llvm::to_string(Inputs.ASTSelection));
+ }
+ std::string title() const override { return "Show selection tree"; }
+ Intent intent() const override { return Info; }
+ bool hidden() const override { return true; }
+};
+REGISTER_TWEAK(ShowSelectionTree);
+
+/// Shows the layout of the RecordDecl under the cursor.
+/// Input:
+/// struct X { int foo; };
+/// ^^^^^^^^
+/// Message:
+/// 0 | struct S
+/// 0 | int foo
+/// | [sizeof=4, dsize=4, align=4,
+/// | nvsize=4, nvalign=4]
+class DumpRecordLayout : public Tweak {
+public:
+ const char *id() const override final;
+
+ bool prepare(const Selection &Inputs) override {
+ if (auto *Node = Inputs.ASTSelection.commonAncestor())
+ if (auto *D = Node->ASTNode.get<Decl>())
+ Record = dyn_cast<RecordDecl>(D);
+ return Record && Record->isThisDeclarationADefinition() &&
+ !Record->isDependentType();
+ }
+ Expected<Effect> apply(const Selection &Inputs) override {
+ std::string Str;
+ llvm::raw_string_ostream OS(Str);
+ Inputs.AST.getASTContext().DumpRecordLayout(Record, OS);
+ return Effect::showMessage(std::move(OS.str()));
+ }
+ std::string title() const override {
+ return llvm::formatv(
+ "Show {0} layout",
+ TypeWithKeyword::getTagTypeKindName(Record->getTagKind()));
+ }
+ Intent intent() const override { return Info; }
+
+private:
+ const RecordDecl *Record = nullptr;
+};
+REGISTER_TWEAK(DumpRecordLayout);
+
+} // namespace
+} // namespace clangd
+} // namespace clang
Modified: clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp (original)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/RawStringLiteral.cpp Tue Jun 18 06:37:54 2019
@@ -39,8 +39,9 @@ public:
const char *id() const override final;
bool prepare(const Selection &Inputs) override;
- Expected<tooling::Replacements> apply(const Selection &Inputs) override;
- std::string title() const override;
+ Expected<Effect> apply(const Selection &Inputs) override;
+ std::string title() const override { return "Convert to raw string"; }
+ Intent intent() const override { return Refactor; }
private:
const clang::StringLiteral *Str = nullptr;
@@ -86,16 +87,13 @@ bool RawStringLiteral::prepare(const Sel
needsRaw(Str->getBytes()) && canBeRaw(Str->getBytes());
}
-Expected<tooling::Replacements>
-RawStringLiteral::apply(const Selection &Inputs) {
- return tooling::Replacements(
+Expected<Tweak::Effect> RawStringLiteral::apply(const Selection &Inputs) {
+ return Effect::applyEdit(tooling::Replacements(
tooling::Replacement(Inputs.AST.getSourceManager(), Str,
("R\"(" + Str->getBytes() + ")\"").str(),
- Inputs.AST.getASTContext().getLangOpts()));
+ Inputs.AST.getASTContext().getLangOpts())));
}
-std::string RawStringLiteral::title() const { return "Convert to raw string"; }
-
} // namespace
} // namespace clangd
} // namespace clang
Modified: clang-tools-extra/trunk/clangd/refactor/tweaks/SwapIfBranches.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/refactor/tweaks/SwapIfBranches.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/refactor/tweaks/SwapIfBranches.cpp (original)
+++ clang-tools-extra/trunk/clangd/refactor/tweaks/SwapIfBranches.cpp Tue Jun 18 06:37:54 2019
@@ -37,8 +37,9 @@ public:
const char *id() const override final;
bool prepare(const Selection &Inputs) override;
- Expected<tooling::Replacements> apply(const Selection &Inputs) override;
- std::string title() const override;
+ Expected<Effect> apply(const Selection &Inputs) override;
+ std::string title() const override { return "Swap if branches"; }
+ Intent intent() const override { return Refactor; }
private:
const IfStmt *If = nullptr;
@@ -60,7 +61,7 @@ bool SwapIfBranches::prepare(const Selec
dyn_cast_or_null<CompoundStmt>(If->getElse());
}
-Expected<tooling::Replacements> SwapIfBranches::apply(const Selection &Inputs) {
+Expected<Tweak::Effect> SwapIfBranches::apply(const Selection &Inputs) {
auto &Ctx = Inputs.AST.getASTContext();
auto &SrcMgr = Inputs.AST.getSourceManager();
@@ -89,11 +90,9 @@ Expected<tooling::Replacements> SwapIfBr
ElseRng->getBegin(),
ElseCode.size(), ThenCode)))
return std::move(Err);
- return Result;
+ return Effect::applyEdit(Result);
}
-std::string SwapIfBranches::title() const { return "Swap if branches"; }
-
} // namespace
} // namespace clangd
} // namespace clang
Modified: clang-tools-extra/trunk/clangd/tool/ClangdMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/tool/ClangdMain.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/tool/ClangdMain.cpp (original)
+++ clang-tools-extra/trunk/clangd/tool/ClangdMain.cpp Tue Jun 18 06:37:54 2019
@@ -263,6 +263,11 @@ static llvm::cl::opt<CodeCompleteOptions
"Always used text-based completion")),
llvm::cl::init(CodeCompleteOptions().RunParser), llvm::cl::Hidden);
+static llvm::cl::opt<bool> HiddenFeatures(
+ "hidden-features",
+ llvm::cl::desc("Enable hidden features mostly useful to clangd developers"),
+ llvm::cl::init(false), llvm::cl::Hidden);
+
namespace {
/// \brief Supports a test URI scheme with relaxed constraints for lit tests.
@@ -459,6 +464,7 @@ int main(int argc, char *argv[]) {
}
Opts.StaticIndex = StaticIdx.get();
Opts.AsyncThreadsCount = WorkerThreadsCount;
+ Opts.HiddenFeatures = HiddenFeatures;
clangd::CodeCompleteOptions CCOpts;
CCOpts.IncludeIneligibleResults = IncludeIneligibleResults;
Modified: clang-tools-extra/trunk/clangd/unittests/SelectionTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/SelectionTests.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/SelectionTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/SelectionTests.cpp Tue Jun 18 06:37:54 2019
@@ -216,6 +216,16 @@ TEST(SelectionTest, CommonAncestor) {
}
}
+// Regression test: this used to match the injected X, not the outer X.
+TEST(SelectionTest, InjectedClassName) {
+ const char* Code = "struct ^X { int x; };";
+ auto AST = TestTU::withCode(Annotations(Code).code()).build();
+ auto T = makeSelectionTree(Code, AST);
+ ASSERT_EQ("CXXRecordDecl", nodeKind(T.commonAncestor())) << T;
+ auto *D = dyn_cast<CXXRecordDecl>(T.commonAncestor()->ASTNode.get<Decl>());
+ EXPECT_FALSE(D->isInjectedClassName());
+}
+
TEST(SelectionTest, Selected) {
// Selection with ^marks^.
// Partially selected nodes marked with a [[range]].
Modified: clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp?rev=363680&r1=363679&r2=363680&view=diff
==============================================================================
--- clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp (original)
+++ clang-tools-extra/trunk/clangd/unittests/TweakTests.cpp Tue Jun 18 06:37:54 2019
@@ -75,7 +75,8 @@ void checkAvailable(StringRef ID, llvm::
void checkNotAvailable(StringRef ID, llvm::StringRef Input) {
return checkAvailable(ID, Input, /*Available=*/false);
}
-llvm::Expected<std::string> apply(StringRef ID, llvm::StringRef Input) {
+
+llvm::Expected<Tweak::Effect> apply(StringRef ID, llvm::StringRef Input) {
Annotations Code(Input);
Range SelectionRng;
if (Code.points().size() != 0) {
@@ -97,15 +98,30 @@ llvm::Expected<std::string> apply(String
auto T = prepareTweak(ID, S);
if (!T)
return T.takeError();
- auto Replacements = (*T)->apply(S);
- if (!Replacements)
- return Replacements.takeError();
- return applyAllReplacements(Code.code(), *Replacements);
+ return (*T)->apply(S);
+}
+
+llvm::Expected<std::string> applyEdit(StringRef ID, llvm::StringRef Input) {
+ auto Effect = apply(ID, Input);
+ if (!Effect)
+ return Effect.takeError();
+ if (!Effect->ApplyEdit)
+ return llvm::createStringError(llvm::inconvertibleErrorCode(),
+ "No replacements");
+ Annotations Code(Input);
+ return applyAllReplacements(Code.code(), *Effect->ApplyEdit);
+}
+
+std::string getMessage(StringRef ID, llvm::StringRef Input) {
+ auto Effect = apply(ID, Input);
+ if (!Effect)
+ return "error: " + llvm::toString(Effect.takeError());
+ return Effect->ShowMessage.getValueOr("no message produced!");
}
void checkTransform(llvm::StringRef ID, llvm::StringRef Input,
std::string Output) {
- auto Result = apply(ID, Input);
+ auto Result = applyEdit(ID, Input);
ASSERT_TRUE(bool(Result)) << llvm::toString(Result.takeError()) << Input;
EXPECT_EQ(Output, std::string(*Result)) << Input;
}
@@ -216,6 +232,49 @@ literal)";
checkTransform(ID, Input, Output);
}
+TEST(TweakTest, DumpAST) {
+ llvm::StringLiteral ID = "DumpAST";
+
+ checkAvailable(ID, "^int f^oo() { re^turn 2 ^+ 2; }");
+ checkNotAvailable(ID, "/*c^omment*/ int foo() return 2 ^ + 2; }");
+
+ const char *Input = "int x = 2 ^+ 2;";
+ const char *Output = R"(BinaryOperator.*'\+'.*
+.*IntegerLiteral.*'int' 2.*
+.*IntegerLiteral.*'int' 2.*)";
+ EXPECT_THAT(getMessage(ID, Input), ::testing::MatchesRegex(Output));
+}
+
+TEST(TweakTest, ShowSelectionTree) {
+ llvm::StringLiteral ID = "ShowSelectionTree";
+
+ checkAvailable(ID, "^int f^oo() { re^turn 2 ^+ 2; }");
+ checkNotAvailable(ID, "/*c^omment*/ int foo() return 2 ^ + 2; }");
+
+ const char *Input = "int fcall(int); int x = fca[[ll(2 +]]2);";
+ const char *Output = R"(TranslationUnitDecl
+ VarDecl int x = fcall(2 + 2)
+ .CallExpr fcall(2 + 2)
+ ImplicitCastExpr fcall
+ .DeclRefExpr fcall
+ .BinaryOperator 2 + 2
+ *IntegerLiteral 2
+)";
+ EXPECT_EQ(Output, getMessage(ID, Input));
+}
+
+TEST(TweakTest, DumpRecordLayout) {
+ llvm::StringLiteral ID = "DumpRecordLayout";
+ checkAvailable(ID, "^s^truct ^X ^{ int x; ^};");
+ checkNotAvailable(ID, "struct X { int ^a; };");
+ checkNotAvailable(ID, "struct ^X;");
+ checkNotAvailable(ID, "template <typename T> struct ^X { T t; };");
+ checkNotAvailable(ID, "enum ^X {};");
+
+ const char *Input = "struct ^X { int x; int y; }";
+ EXPECT_THAT(getMessage(ID, Input), ::testing::HasSubstr("0 | int x"));
+}
+
} // namespace
} // namespace clangd
} // namespace clang
More information about the cfe-commits
mailing list