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