Index: clang-tidy/utils/LexerUtils.h =================================================================== --- clang-tidy/utils/LexerUtils.h +++ clang-tidy/utils/LexerUtils.h @@ -22,6 +22,9 @@ Token getPreviousToken(const ASTContext &Context, SourceLocation Location, bool SkipComments = true); +/// Get source code text for statement. +Optional getStmtText(const Stmt* Statement, const SourceManager& SM); + } // namespace lexer } // namespace utils } // namespace tidy Index: clang-tidy/utils/LexerUtils.cpp =================================================================== --- clang-tidy/utils/LexerUtils.cpp +++ clang-tidy/utils/LexerUtils.cpp @@ -35,6 +35,20 @@ return Token; } +Optional getStmtText(const Stmt* Statement, const SourceManager& SM) { + if (!Statement) { + return llvm::NoneType(); + } + + bool Error = false; + auto Ret = Lexer::getSourceText( + CharSourceRange::getTokenRange(Statement->getSourceRange()), + SM, LangOptions(), + &Error); + + return Error ? llvm::NoneType() : Optional(Ret); +} + } // namespace lexer } // namespace utils } // namespace tidy Index: unittests/clang-tidy/CMakeLists.txt =================================================================== --- unittests/clang-tidy/CMakeLists.txt +++ unittests/clang-tidy/CMakeLists.txt @@ -11,6 +11,7 @@ ClangTidyOptionsTest.cpp IncludeInserterTest.cpp GoogleModuleTest.cpp + LexerUtilsTest.cpp LLVMModuleTest.cpp NamespaceAliaserTest.cpp ObjCModuleTest.cpp Index: unittests/clang-tidy/LexerUtilsTest.cpp =================================================================== --- /dev/null +++ unittests/clang-tidy/LexerUtilsTest.cpp @@ -0,0 +1,51 @@ +#include "ClangTidyTest.h" +#include "clang/Tooling/Tooling.h" +#include "utils/LexerUtils.h" +#include "gtest/gtest.h" + +namespace clang { +namespace tidy { +namespace test { + +class GetStmtTextTest : public ::testing::Test { +protected: + GetStmtTextTest() + : Unit(CheckASTUnitNotNull(tooling::buildASTFromCode("void foo() { int bar = 0; }"))), + SM(Unit->getSourceManager()) + {} + + std::unique_ptr CheckASTUnitNotNull(std::unique_ptr Unit) { + EXPECT_TRUE(Unit); + return Unit; + } + + std::unique_ptr Unit; + SourceManager& SM; +}; + +TEST_F(GetStmtTextTest, NullStatement) { + EXPECT_EQ(llvm::NoneType(), utils::lexer::getStmtText(nullptr, SM)); +} + +TEST_F(GetStmtTextTest, SimpleStatement) { + auto FooIdent = &Unit->getASTContext().Idents.getOwn("foo"); + auto FooDeclName = Unit->getASTContext().DeclarationNames.getIdentifier(FooIdent); + auto FooLookup = Unit->getASTContext().getTranslationUnitDecl()->lookup(FooDeclName); + auto FooFunction = dyn_cast_or_null(FooLookup.front()); + EXPECT_TRUE(FooFunction); + + auto FooBody = dyn_cast_or_null(FooFunction->getBody()); + EXPECT_TRUE(FooBody); + EXPECT_TRUE(FooBody->body_begin()); + + auto DeclStmt = *FooBody->body_begin(); + + + auto Res = utils::lexer::getStmtText(DeclStmt, SM); + EXPECT_TRUE(Res.hasValue()); + EXPECT_EQ("int bar = 0;", *Res); +} + +} // namespace test +} // namespace tidy +} // namespace clang