1 //===---- QueryTest.cpp - clang-query test --------------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "Query.h" 11 #include "QueryParser.h" 12 #include "QuerySession.h" 13 #include "clang/ASTMatchers/ASTMatchers.h" 14 #include "clang/ASTMatchers/Dynamic/VariantValue.h" 15 #include "clang/Frontend/ASTUnit.h" 16 #include "clang/Tooling/Tooling.h" 17 #include "llvm/ADT/STLExtras.h" 18 #include "llvm/Support/raw_ostream.h" 19 #include "gtest/gtest.h" 20 #include <string> 21 22 using namespace clang; 23 using namespace clang::ast_matchers; 24 using namespace clang::ast_matchers::dynamic; 25 using namespace clang::query; 26 using namespace clang::tooling; 27 28 class QueryEngineTest : public ::testing::Test { 29 ArrayRef<std::unique_ptr<ASTUnit>> mkASTUnit2(std::unique_ptr<ASTUnit> a, 30 std::unique_ptr<ASTUnit> b) { 31 ASTs[0] = std::move(a); 32 ASTs[1] = std::move(b); 33 return ArrayRef<std::unique_ptr<ASTUnit>>(ASTs); 34 } 35 36 protected: 37 QueryEngineTest() 38 : S(mkASTUnit2(buildASTFromCode("void foo1(void) {}\nvoid foo2(void) {}", 39 "foo.cc"), 40 buildASTFromCode("void bar1(void) {}\nvoid bar2(void) {}", 41 "bar.cc"))), 42 OS(Str) {} 43 44 std::unique_ptr<ASTUnit> ASTs[2]; 45 QuerySession S; 46 47 std::string Str; 48 llvm::raw_string_ostream OS; 49 }; 50 51 TEST_F(QueryEngineTest, Basic) { 52 DynTypedMatcher FnMatcher = functionDecl(); 53 DynTypedMatcher FooMatcher = functionDecl(hasName("foo1")); 54 55 std::string FooMatcherString = "functionDecl(hasName(\"foo1\"))"; 56 57 EXPECT_TRUE(NoOpQuery().run(OS, S)); 58 59 EXPECT_EQ("", OS.str()); 60 61 Str.clear(); 62 63 EXPECT_FALSE(InvalidQuery("Parse error").run(OS, S)); 64 65 EXPECT_EQ("Parse error\n", OS.str()); 66 67 Str.clear(); 68 69 EXPECT_TRUE(HelpQuery().run(OS, S)); 70 71 EXPECT_TRUE(OS.str().find("Available commands:") != std::string::npos); 72 73 Str.clear(); 74 75 EXPECT_TRUE(MatchQuery("functionDecl()", FnMatcher).run(OS, S)); 76 77 EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") != 78 std::string::npos); 79 EXPECT_TRUE(OS.str().find("foo.cc:2:1: note: \"root\" binds here") != 80 std::string::npos); 81 EXPECT_TRUE(OS.str().find("bar.cc:1:1: note: \"root\" binds here") != 82 std::string::npos); 83 EXPECT_TRUE(OS.str().find("bar.cc:2:1: note: \"root\" binds here") != 84 std::string::npos); 85 EXPECT_TRUE(OS.str().find("4 matches.") != std::string::npos); 86 87 Str.clear(); 88 89 EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); 90 91 EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") != 92 std::string::npos); 93 EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos); 94 95 Str.clear(); 96 97 EXPECT_TRUE( 98 SetExclusiveOutputQuery(&QuerySession::PrintOutput).run(OS, S)); 99 EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); 100 101 EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") != 102 std::string::npos); 103 104 Str.clear(); 105 106 EXPECT_TRUE( 107 SetExclusiveOutputQuery(&QuerySession::DetailedASTOutput).run(OS, S)); 108 EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); 109 110 EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos); 111 112 Str.clear(); 113 114 EXPECT_TRUE(EnableOutputQuery(&QuerySession::DiagOutput).run(OS, S)); 115 EXPECT_TRUE(EnableOutputQuery(&QuerySession::DetailedASTOutput).run(OS, S)); 116 EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); 117 118 { 119 auto Output = OS.str(); 120 EXPECT_TRUE(Output.find("FunctionDecl") != std::string::npos); 121 EXPECT_TRUE(Output.find("foo.cc:1:1: note: \"root\" binds here") != 122 std::string::npos); 123 } 124 125 Str.clear(); 126 127 EXPECT_TRUE(SetQuery<bool>(&QuerySession::BindRoot, false).run(OS, S)); 128 EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S)); 129 130 EXPECT_TRUE(OS.str().find("No bindings.") != std::string::npos); 131 132 Str.clear(); 133 134 EXPECT_FALSE(MatchQuery("isMain()", isMain()).run(OS, S)); 135 136 EXPECT_EQ("Not a valid top-level matcher.\n", OS.str()); 137 } 138 139 TEST_F(QueryEngineTest, LetAndMatch) { 140 EXPECT_TRUE(QueryParser::parse("let x \"foo1\"", S)->run(OS, S)); 141 EXPECT_EQ("", OS.str()); 142 Str.clear(); 143 144 EXPECT_TRUE(QueryParser::parse("let y hasName(x)", S)->run(OS, S)); 145 EXPECT_EQ("", OS.str()); 146 Str.clear(); 147 148 EXPECT_TRUE(QueryParser::parse("match functionDecl(y)", S)->run(OS, S)); 149 EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") != 150 std::string::npos); 151 EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos); 152 Str.clear(); 153 154 EXPECT_TRUE(QueryParser::parse("unlet x", S)->run(OS, S)); 155 EXPECT_EQ("", OS.str()); 156 Str.clear(); 157 158 EXPECT_FALSE(QueryParser::parse("let y hasName(x)", S)->run(OS, S)); 159 EXPECT_EQ("1:2: Error parsing argument 1 for matcher hasName.\n" 160 "1:10: Value not found: x\n", OS.str()); 161 Str.clear(); 162 } 163