Author: ymandel Date: Fri Apr 5 07:05:03 2019 New Revision: 357764 URL: http://llvm.org/viewvc/llvm-project?rev=357764&view=rev Log: [LibTooling] Add "SourceCode" library for functions relating to source-code manipulation.
Summary: Introduces a utility library in Refactoring/ to collect routines related to source-code manipulation. In this change, we move "extended-range" functions from the FixIt library (in clangTooling) to this new library. We need to use this functionality in Refactoring/ and cannot access it if it resides in Tooling/, because that would cause clangToolingRefactor to depend on clangTooling, which would be a circular dependency. Reviewers: ilya-biryukov, ioeric Reviewed By: ilya-biryukov Subscribers: mgorny, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D60269 Added: cfe/trunk/include/clang/Tooling/Refactoring/SourceCode.h cfe/trunk/lib/Tooling/Refactoring/SourceCode.cpp cfe/trunk/unittests/Tooling/SourceCodeTest.cpp Modified: cfe/trunk/include/clang/Tooling/FixIt.h cfe/trunk/lib/Tooling/FixIt.cpp cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt cfe/trunk/unittests/Tooling/CMakeLists.txt cfe/trunk/unittests/Tooling/FixItTest.cpp Modified: cfe/trunk/include/clang/Tooling/FixIt.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/FixIt.h?rev=357764&r1=357763&r2=357764&view=diff ============================================================================== --- cfe/trunk/include/clang/Tooling/FixIt.h (original) +++ cfe/trunk/include/clang/Tooling/FixIt.h Fri Apr 5 07:05:03 2019 @@ -20,7 +20,6 @@ #define LLVM_CLANG_TOOLING_FIXIT_H #include "clang/AST/ASTContext.h" -#include "clang/Basic/TokenKinds.h" namespace clang { namespace tooling { @@ -44,11 +43,6 @@ inline CharSourceRange getSourceRange(co template <typename T> CharSourceRange getSourceRange(const T &Node) { return CharSourceRange::getTokenRange(Node.getSourceRange()); } - -/// Extends \p Range to include the token \p Next, if it immediately follows the -/// end of the range. Otherwise, returns \p Range unchanged. -CharSourceRange maybeExtendRange(CharSourceRange Range, tok::TokenKind Next, - ASTContext &Context); } // end namespace internal /// Returns a textual representation of \p Node. @@ -57,44 +51,6 @@ StringRef getText(const T &Node, const A return internal::getText(internal::getSourceRange(Node), Context); } -/// Returns the source range spanning the node, extended to include \p Next, if -/// it immediately follows \p Node. Otherwise, returns the normal range of \p -/// Node. See comments on `getExtendedText()` for examples. -template <typename T> -CharSourceRange getExtendedRange(const T &Node, tok::TokenKind Next, - ASTContext &Context) { - return internal::maybeExtendRange(internal::getSourceRange(Node), Next, - Context); -} - -/// Returns the source text of the node, extended to include \p Next, if it -/// immediately follows the node. Otherwise, returns the text of just \p Node. -/// -/// For example, given statements S1 and S2 below: -/// \code -/// { -/// // S1: -/// if (!x) return foo(); -/// // S2: -/// if (!x) { return 3; } -/// } -/// \endcode -/// then -/// \code -/// getText(S1, Context) = "if (!x) return foo()" -/// getExtendedText(S1, tok::TokenKind::semi, Context) -/// = "if (!x) return foo();" -/// getExtendedText(*S1.getThen(), tok::TokenKind::semi, Context) -/// = "return foo();" -/// getExtendedText(*S2.getThen(), tok::TokenKind::semi, Context) -/// = getText(S2, Context) = "{ return 3; }" -/// \endcode -template <typename T> -StringRef getExtendedText(const T &Node, tok::TokenKind Next, - ASTContext &Context) { - return internal::getText(getExtendedRange(Node, Next, Context), Context); -} - // Returns a FixItHint to remove \p Node. // TODO: Add support for related syntactical elements (i.e. comments, ...). template <typename T> FixItHint createRemoval(const T &Node) { Added: cfe/trunk/include/clang/Tooling/Refactoring/SourceCode.h URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Tooling/Refactoring/SourceCode.h?rev=357764&view=auto ============================================================================== --- cfe/trunk/include/clang/Tooling/Refactoring/SourceCode.h (added) +++ cfe/trunk/include/clang/Tooling/Refactoring/SourceCode.h Fri Apr 5 07:05:03 2019 @@ -0,0 +1,77 @@ +//===--- SourceCode.h - Source code manipulation routines -------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides functions that simplify extraction of source code. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H +#define LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H + +#include "clang/AST/ASTContext.h" +#include "clang/Basic/SourceLocation.h" +#include "clang/Basic/TokenKinds.h" + +namespace clang { +namespace tooling { + +/// Extends \p Range to include the token \p Next, if it immediately follows the +/// end of the range. Otherwise, returns \p Range unchanged. +CharSourceRange maybeExtendRange(CharSourceRange Range, tok::TokenKind Next, + ASTContext &Context); + +/// Returns the source range spanning the node, extended to include \p Next, if +/// it immediately follows \p Node. Otherwise, returns the normal range of \p +/// Node. See comments on `getExtendedText()` for examples. +template <typename T> +CharSourceRange getExtendedRange(const T &Node, tok::TokenKind Next, + ASTContext &Context) { + return maybeExtendRange(CharSourceRange::getTokenRange(Node.getSourceRange()), + Next, Context); +} + +/// Returns the source-code text in the specified range. +StringRef getText(CharSourceRange Range, const ASTContext &Context); + +/// Returns the source-code text corresponding to \p Node. +template <typename T> +StringRef getText(const T &Node, const ASTContext &Context) { + return getText(CharSourceRange::getTokenRange(Node.getSourceRange()), + Context); +} + +/// Returns the source text of the node, extended to include \p Next, if it +/// immediately follows the node. Otherwise, returns the text of just \p Node. +/// +/// For example, given statements S1 and S2 below: +/// \code +/// { +/// // S1: +/// if (!x) return foo(); +/// // S2: +/// if (!x) { return 3; } +/// } +/// \endcode +/// then +/// \code +/// getText(S1, Context) = "if (!x) return foo()" +/// getExtendedText(S1, tok::TokenKind::semi, Context) +/// = "if (!x) return foo();" +/// getExtendedText(*S1.getThen(), tok::TokenKind::semi, Context) +/// = "return foo();" +/// getExtendedText(*S2.getThen(), tok::TokenKind::semi, Context) +/// = getText(S2, Context) = "{ return 3; }" +/// \endcode +template <typename T> +StringRef getExtendedText(const T &Node, tok::TokenKind Next, + ASTContext &Context) { + return getText(getExtendedRange(Node, Next, Context), Context); +} +} // namespace tooling +} // namespace clang +#endif // LLVM_CLANG_TOOLING_REFACTOR_SOURCE_CODE_H Modified: cfe/trunk/lib/Tooling/FixIt.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/FixIt.cpp?rev=357764&r1=357763&r2=357764&view=diff ============================================================================== --- cfe/trunk/lib/Tooling/FixIt.cpp (original) +++ cfe/trunk/lib/Tooling/FixIt.cpp Fri Apr 5 07:05:03 2019 @@ -22,15 +22,6 @@ StringRef getText(CharSourceRange Range, return Lexer::getSourceText(Range, Context.getSourceManager(), Context.getLangOpts()); } - -CharSourceRange maybeExtendRange(CharSourceRange Range, tok::TokenKind Next, - ASTContext &Context) { - Optional<Token> Tok = Lexer::findNextToken( - Range.getEnd(), Context.getSourceManager(), Context.getLangOpts()); - if (!Tok || !Tok->is(Next)) - return Range; - return CharSourceRange::getTokenRange(Range.getBegin(), Tok->getLocation()); -} } // namespace internal } // end namespace fixit Modified: cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt?rev=357764&r1=357763&r2=357764&view=diff ============================================================================== --- cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt (original) +++ cfe/trunk/lib/Tooling/Refactoring/CMakeLists.txt Fri Apr 5 07:05:03 2019 @@ -12,6 +12,7 @@ add_clang_library(clangToolingRefactor Rename/USRFinder.cpp Rename/USRFindingAction.cpp Rename/USRLocFinder.cpp + SourceCode.cpp LINK_LIBS clangAST Added: cfe/trunk/lib/Tooling/Refactoring/SourceCode.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Tooling/Refactoring/SourceCode.cpp?rev=357764&view=auto ============================================================================== --- cfe/trunk/lib/Tooling/Refactoring/SourceCode.cpp (added) +++ cfe/trunk/lib/Tooling/Refactoring/SourceCode.cpp Fri Apr 5 07:05:03 2019 @@ -0,0 +1,31 @@ +//===--- SourceCode.cpp - Source code manipulation routines -----*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file provides functions that simplify extraction of source code. +// +//===----------------------------------------------------------------------===// +#include "clang/Tooling/Refactoring/SourceCode.h" +#include "clang/Lex/Lexer.h" + +using namespace clang; + +StringRef clang::tooling::getText(CharSourceRange Range, + const ASTContext &Context) { + return Lexer::getSourceText(Range, Context.getSourceManager(), + Context.getLangOpts()); +} + +CharSourceRange clang::tooling::maybeExtendRange(CharSourceRange Range, + tok::TokenKind Next, + ASTContext &Context) { + Optional<Token> Tok = Lexer::findNextToken( + Range.getEnd(), Context.getSourceManager(), Context.getLangOpts()); + if (!Tok || !Tok->is(Next)) + return Range; + return CharSourceRange::getTokenRange(Range.getBegin(), Tok->getLocation()); +} Modified: cfe/trunk/unittests/Tooling/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/CMakeLists.txt?rev=357764&r1=357763&r2=357764&view=diff ============================================================================== --- cfe/trunk/unittests/Tooling/CMakeLists.txt (original) +++ cfe/trunk/unittests/Tooling/CMakeLists.txt Fri Apr 5 07:05:03 2019 @@ -49,6 +49,7 @@ add_clang_unittest(ToolingTests RefactoringTest.cpp ReplacementsYamlTest.cpp RewriterTest.cpp + SourceCodeTest.cpp ToolingTest.cpp ) Modified: cfe/trunk/unittests/Tooling/FixItTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/FixItTest.cpp?rev=357764&r1=357763&r2=357764&view=diff ============================================================================== --- cfe/trunk/unittests/Tooling/FixItTest.cpp (original) +++ cfe/trunk/unittests/Tooling/FixItTest.cpp Fri Apr 5 07:05:03 2019 @@ -13,7 +13,6 @@ using namespace clang; using tooling::fixit::getText; -using tooling::fixit::getExtendedText; using tooling::fixit::createRemoval; using tooling::fixit::createReplacement; @@ -78,34 +77,6 @@ TEST(FixItTest, getTextWithMacro) { "void foo(int x, int y) { FOO(x,y) }"); } -TEST(FixItTest, getExtendedText) { - CallsVisitor Visitor; - - Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { - EXPECT_EQ("foo(x, y);", - getExtendedText(*CE, tok::TokenKind::semi, *Context)); - - Expr *P0 = CE->getArg(0); - Expr *P1 = CE->getArg(1); - EXPECT_EQ("x", getExtendedText(*P0, tok::TokenKind::semi, *Context)); - EXPECT_EQ("x,", getExtendedText(*P0, tok::TokenKind::comma, *Context)); - EXPECT_EQ("y", getExtendedText(*P1, tok::TokenKind::semi, *Context)); - }; - Visitor.runOver("void foo(int x, int y) { foo(x, y); }"); - Visitor.runOver("void foo(int x, int y) { if (true) foo(x, y); }"); - Visitor.runOver("int foo(int x, int y) { if (true) return 3 + foo(x, y); }"); - Visitor.runOver("void foo(int x, int y) { for (foo(x, y);;) ++x; }"); - Visitor.runOver( - "bool foo(int x, int y) { for (;foo(x, y);) x = 1; return true; }"); - - Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { - EXPECT_EQ("foo()", getExtendedText(*CE, tok::TokenKind::semi, *Context)); - }; - Visitor.runOver("bool foo() { if (foo()) return true; return false; }"); - Visitor.runOver("void foo() { int x; for (;; foo()) ++x; }"); - Visitor.runOver("int foo() { return foo() + 3; }"); -} - TEST(FixItTest, createRemoval) { CallsVisitor Visitor; Added: cfe/trunk/unittests/Tooling/SourceCodeTest.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/unittests/Tooling/SourceCodeTest.cpp?rev=357764&view=auto ============================================================================== --- cfe/trunk/unittests/Tooling/SourceCodeTest.cpp (added) +++ cfe/trunk/unittests/Tooling/SourceCodeTest.cpp Fri Apr 5 07:05:03 2019 @@ -0,0 +1,97 @@ +//===- unittest/Tooling/SourceCodeTest.cpp --------------------------------===// +// +// 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 "TestVisitor.h" +#include "clang/Basic/Diagnostic.h" +#include "clang/Tooling/Refactoring/SourceCode.h" + +using namespace clang; + +using tooling::getText; +using tooling::getExtendedText; + +namespace { + +struct CallsVisitor : TestVisitor<CallsVisitor> { + bool VisitCallExpr(CallExpr *Expr) { + OnCall(Expr, Context); + return true; + } + + std::function<void(CallExpr *, ASTContext *Context)> OnCall; +}; + +TEST(SourceCodeTest, getText) { + CallsVisitor Visitor; + + Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { + EXPECT_EQ("foo(x, y)", getText(*CE, *Context)); + }; + Visitor.runOver("void foo(int x, int y) { foo(x, y); }"); + + Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { + EXPECT_EQ("APPLY(foo, x, y)", getText(*CE, *Context)); + }; + Visitor.runOver("#define APPLY(f, x, y) f(x, y)\n" + "void foo(int x, int y) { APPLY(foo, x, y); }"); +} + +TEST(SourceCodeTest, getTextWithMacro) { + CallsVisitor Visitor; + + Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { + EXPECT_EQ("F OO", getText(*CE, *Context)); + Expr *P0 = CE->getArg(0); + Expr *P1 = CE->getArg(1); + EXPECT_EQ("", getText(*P0, *Context)); + EXPECT_EQ("", getText(*P1, *Context)); + }; + Visitor.runOver("#define F foo(\n" + "#define OO x, y)\n" + "void foo(int x, int y) { F OO ; }"); + + Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { + EXPECT_EQ("", getText(*CE, *Context)); + Expr *P0 = CE->getArg(0); + Expr *P1 = CE->getArg(1); + EXPECT_EQ("x", getText(*P0, *Context)); + EXPECT_EQ("y", getText(*P1, *Context)); + }; + Visitor.runOver("#define FOO(x, y) (void)x; (void)y; foo(x, y);\n" + "void foo(int x, int y) { FOO(x,y) }"); +} + +TEST(SourceCodeTest, getExtendedText) { + CallsVisitor Visitor; + + Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { + EXPECT_EQ("foo(x, y);", + getExtendedText(*CE, tok::TokenKind::semi, *Context)); + + Expr *P0 = CE->getArg(0); + Expr *P1 = CE->getArg(1); + EXPECT_EQ("x", getExtendedText(*P0, tok::TokenKind::semi, *Context)); + EXPECT_EQ("x,", getExtendedText(*P0, tok::TokenKind::comma, *Context)); + EXPECT_EQ("y", getExtendedText(*P1, tok::TokenKind::semi, *Context)); + }; + Visitor.runOver("void foo(int x, int y) { foo(x, y); }"); + Visitor.runOver("void foo(int x, int y) { if (true) foo(x, y); }"); + Visitor.runOver("int foo(int x, int y) { if (true) return 3 + foo(x, y); }"); + Visitor.runOver("void foo(int x, int y) { for (foo(x, y);;) ++x; }"); + Visitor.runOver( + "bool foo(int x, int y) { for (;foo(x, y);) x = 1; return true; }"); + + Visitor.OnCall = [](CallExpr *CE, ASTContext *Context) { + EXPECT_EQ("foo()", getExtendedText(*CE, tok::TokenKind::semi, *Context)); + }; + Visitor.runOver("bool foo() { if (foo()) return true; return false; }"); + Visitor.runOver("void foo() { int x; for (;; foo()) ++x; }"); + Visitor.runOver("int foo() { return foo() + 3; }"); +} + +} // end anonymous namespace _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits