xref: /llvm-project/clang-tools-extra/unittests/clang-query/QueryEngineTest.cpp (revision be6b63b685fd3e6aa00bab5932ed85847d85633c)
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<ASTUnit *> mkASTUnit2(ASTUnit *a, ASTUnit *b) {
30     ASTs[0] = a;
31     ASTs[1] = b;
32     return ASTs;
33   }
34 
35 protected:
36   QueryEngineTest()
37       : FooAST(buildASTFromCode("void foo1(void) {}\nvoid foo2(void) {}",
38                                 "foo.cc")),
39         BarAST(buildASTFromCode("void bar1(void) {}\nvoid bar2(void) {}",
40                                 "bar.cc")),
41         S(mkASTUnit2(FooAST.get(), BarAST.get())), OS(Str) {}
42 
43   std::unique_ptr<ASTUnit> FooAST;
44   std::unique_ptr<ASTUnit> BarAST;
45   ASTUnit *ASTs[2];
46   QuerySession S;
47 
48   std::string Str;
49   llvm::raw_string_ostream OS;
50 };
51 
52 TEST_F(QueryEngineTest, Basic) {
53   DynTypedMatcher FnMatcher = functionDecl();
54   DynTypedMatcher FooMatcher = 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(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(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       SetQuery<OutputKind>(&QuerySession::OutKind, OK_Print).run(OS, S));
98   EXPECT_TRUE(MatchQuery(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(SetQuery<OutputKind>(&QuerySession::OutKind, OK_Dump).run(OS, S));
106   EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
107 
108   EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos);
109 
110   Str.clear();
111 
112   EXPECT_TRUE(SetQuery<bool>(&QuerySession::BindRoot, false).run(OS, S));
113   EXPECT_TRUE(MatchQuery(FooMatcher).run(OS, S));
114 
115   EXPECT_TRUE(OS.str().find("No bindings.") != std::string::npos);
116 
117   Str.clear();
118 
119   EXPECT_FALSE(MatchQuery(isArrow()).run(OS, S));
120 
121   EXPECT_EQ("Not a valid top-level matcher.\n", OS.str());
122 }
123 
124 TEST_F(QueryEngineTest, LetAndMatch) {
125   EXPECT_TRUE(QueryParser::parse("let x \"foo1\"", S)->run(OS, S));
126   EXPECT_EQ("", OS.str());
127   Str.clear();
128 
129   EXPECT_TRUE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
130   EXPECT_EQ("", OS.str());
131   Str.clear();
132 
133   EXPECT_TRUE(QueryParser::parse("match functionDecl(y)", S)->run(OS, S));
134   EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
135               std::string::npos);
136   EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos);
137   Str.clear();
138 
139   EXPECT_TRUE(QueryParser::parse("unlet x", S)->run(OS, S));
140   EXPECT_EQ("", OS.str());
141   Str.clear();
142 
143   EXPECT_FALSE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
144   EXPECT_EQ("1:2: Error parsing argument 1 for matcher hasName.\n"
145             "1:10: Value not found: x\n", OS.str());
146   Str.clear();
147 }
148