xref: /llvm-project/clang-tools-extra/unittests/clang-query/QueryEngineTest.cpp (revision ffe9f00cfea35e3abd937a45ca38c605e02a9a79)
1*ffe9f00cSFangrui Song //===-- QueryEngineTest.cpp - clang-query test ----------------------------===//
28b1265b3SPeter Collingbourne //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68b1265b3SPeter Collingbourne //
78b1265b3SPeter Collingbourne //===----------------------------------------------------------------------===//
88b1265b3SPeter Collingbourne 
98b1265b3SPeter Collingbourne #include "Query.h"
101f6066c9SSamuel Benzaquen #include "QueryParser.h"
118b1265b3SPeter Collingbourne #include "QuerySession.h"
128b1265b3SPeter Collingbourne #include "clang/ASTMatchers/ASTMatchers.h"
138b1265b3SPeter Collingbourne #include "clang/ASTMatchers/Dynamic/VariantValue.h"
148b1265b3SPeter Collingbourne #include "clang/Frontend/ASTUnit.h"
158b1265b3SPeter Collingbourne #include "clang/Tooling/Tooling.h"
168b1265b3SPeter Collingbourne #include "llvm/ADT/STLExtras.h"
178b1265b3SPeter Collingbourne #include "llvm/Support/raw_ostream.h"
188b1265b3SPeter Collingbourne #include "gtest/gtest.h"
198b1265b3SPeter Collingbourne #include <string>
208b1265b3SPeter Collingbourne 
218b1265b3SPeter Collingbourne using namespace clang;
228b1265b3SPeter Collingbourne using namespace clang::ast_matchers;
238b1265b3SPeter Collingbourne using namespace clang::ast_matchers::dynamic;
248b1265b3SPeter Collingbourne using namespace clang::query;
258b1265b3SPeter Collingbourne using namespace clang::tooling;
268b1265b3SPeter Collingbourne 
271f6066c9SSamuel Benzaquen class QueryEngineTest : public ::testing::Test {
mkASTUnit2(std::unique_ptr<ASTUnit> a,std::unique_ptr<ASTUnit> b)2835013fa3SDavid Blaikie   ArrayRef<std::unique_ptr<ASTUnit>> mkASTUnit2(std::unique_ptr<ASTUnit> a,
2935013fa3SDavid Blaikie                                                 std::unique_ptr<ASTUnit> b) {
3035013fa3SDavid Blaikie     ASTs[0] = std::move(a);
3135013fa3SDavid Blaikie     ASTs[1] = std::move(b);
3235013fa3SDavid Blaikie     return ArrayRef<std::unique_ptr<ASTUnit>>(ASTs);
33be6b63b6SNAKAMURA Takumi   }
348b1265b3SPeter Collingbourne 
35be6b63b6SNAKAMURA Takumi protected:
QueryEngineTest()36be6b63b6SNAKAMURA Takumi   QueryEngineTest()
3725286a51SDavid Blaikie       : S(mkASTUnit2(buildASTFromCode("void foo1(void) {}\nvoid foo2(void) {}",
3825286a51SDavid Blaikie                                       "foo.cc"),
3925286a51SDavid Blaikie                      buildASTFromCode("void bar1(void) {}\nvoid bar2(void) {}",
4025286a51SDavid Blaikie                                       "bar.cc"))),
4135013fa3SDavid Blaikie         OS(Str) {}
42be6b63b6SNAKAMURA Takumi 
4335013fa3SDavid Blaikie   std::unique_ptr<ASTUnit> ASTs[2];
44be6b63b6SNAKAMURA Takumi   QuerySession S;
458b1265b3SPeter Collingbourne 
468b1265b3SPeter Collingbourne   std::string Str;
47be6b63b6SNAKAMURA Takumi   llvm::raw_string_ostream OS;
481f6066c9SSamuel Benzaquen };
498b1265b3SPeter Collingbourne 
TEST_F(QueryEngineTest,Basic)501f6066c9SSamuel Benzaquen TEST_F(QueryEngineTest, Basic) {
518b1265b3SPeter Collingbourne   DynTypedMatcher FnMatcher = functionDecl();
528b1265b3SPeter Collingbourne   DynTypedMatcher FooMatcher = functionDecl(hasName("foo1"));
538b1265b3SPeter Collingbourne 
544a5b01ddSStephen Kelly   std::string FooMatcherString = "functionDecl(hasName(\"foo1\"))";
554a5b01ddSStephen Kelly 
568b1265b3SPeter Collingbourne   EXPECT_TRUE(NoOpQuery().run(OS, S));
578b1265b3SPeter Collingbourne 
588b1265b3SPeter Collingbourne   EXPECT_EQ("", OS.str());
598b1265b3SPeter Collingbourne 
608b1265b3SPeter Collingbourne   Str.clear();
618b1265b3SPeter Collingbourne 
628b1265b3SPeter Collingbourne   EXPECT_FALSE(InvalidQuery("Parse error").run(OS, S));
638b1265b3SPeter Collingbourne 
648b1265b3SPeter Collingbourne   EXPECT_EQ("Parse error\n", OS.str());
658b1265b3SPeter Collingbourne 
668b1265b3SPeter Collingbourne   Str.clear();
678b1265b3SPeter Collingbourne 
688b1265b3SPeter Collingbourne   EXPECT_TRUE(HelpQuery().run(OS, S));
698b1265b3SPeter Collingbourne 
708b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("Available commands:") != std::string::npos);
718b1265b3SPeter Collingbourne 
728b1265b3SPeter Collingbourne   Str.clear();
738b1265b3SPeter Collingbourne 
744a5b01ddSStephen Kelly   EXPECT_TRUE(MatchQuery("functionDecl()", FnMatcher).run(OS, S));
758b1265b3SPeter Collingbourne 
768b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
778b1265b3SPeter Collingbourne               std::string::npos);
788b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("foo.cc:2:1: note: \"root\" binds here") !=
798b1265b3SPeter Collingbourne               std::string::npos);
808b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("bar.cc:1:1: note: \"root\" binds here") !=
818b1265b3SPeter Collingbourne               std::string::npos);
828b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("bar.cc:2:1: note: \"root\" binds here") !=
838b1265b3SPeter Collingbourne               std::string::npos);
848b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("4 matches.") != std::string::npos);
858b1265b3SPeter Collingbourne 
868b1265b3SPeter Collingbourne   Str.clear();
878b1265b3SPeter Collingbourne 
884a5b01ddSStephen Kelly   EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S));
898b1265b3SPeter Collingbourne 
908b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
918b1265b3SPeter Collingbourne               std::string::npos);
928b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos);
938b1265b3SPeter Collingbourne 
948b1265b3SPeter Collingbourne   Str.clear();
958b1265b3SPeter Collingbourne 
968b1265b3SPeter Collingbourne   EXPECT_TRUE(
9770d77171SStephen Kelly       SetExclusiveOutputQuery(&QuerySession::PrintOutput).run(OS, S));
984a5b01ddSStephen Kelly   EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S));
998b1265b3SPeter Collingbourne 
1008b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("Binding for \"root\":\nvoid foo1()") !=
1018b1265b3SPeter Collingbourne               std::string::npos);
1028b1265b3SPeter Collingbourne 
1038b1265b3SPeter Collingbourne   Str.clear();
1048b1265b3SPeter Collingbourne 
10551707b21SStephen Kelly   EXPECT_TRUE(
10670d77171SStephen Kelly       SetExclusiveOutputQuery(&QuerySession::DetailedASTOutput).run(OS, S));
1074a5b01ddSStephen Kelly   EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S));
1088b1265b3SPeter Collingbourne 
1098b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("FunctionDecl") != std::string::npos);
1108b1265b3SPeter Collingbourne 
1118b1265b3SPeter Collingbourne   Str.clear();
1128b1265b3SPeter Collingbourne 
113a49fe5d8SStephen Kelly   EXPECT_TRUE(EnableOutputQuery(&QuerySession::DiagOutput).run(OS, S));
114a49fe5d8SStephen Kelly   EXPECT_TRUE(EnableOutputQuery(&QuerySession::DetailedASTOutput).run(OS, S));
115a49fe5d8SStephen Kelly   EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S));
116a49fe5d8SStephen Kelly 
117a49fe5d8SStephen Kelly   {
118a49fe5d8SStephen Kelly     auto Output = OS.str();
119a49fe5d8SStephen Kelly     EXPECT_TRUE(Output.find("FunctionDecl") != std::string::npos);
120a49fe5d8SStephen Kelly     EXPECT_TRUE(Output.find("foo.cc:1:1: note: \"root\" binds here") !=
121a49fe5d8SStephen Kelly                 std::string::npos);
122a49fe5d8SStephen Kelly   }
123a49fe5d8SStephen Kelly 
124a49fe5d8SStephen Kelly   Str.clear();
125a49fe5d8SStephen Kelly 
1268b1265b3SPeter Collingbourne   EXPECT_TRUE(SetQuery<bool>(&QuerySession::BindRoot, false).run(OS, S));
1274a5b01ddSStephen Kelly   EXPECT_TRUE(MatchQuery(FooMatcherString, FooMatcher).run(OS, S));
1288b1265b3SPeter Collingbourne 
1298b1265b3SPeter Collingbourne   EXPECT_TRUE(OS.str().find("No bindings.") != std::string::npos);
1308b1265b3SPeter Collingbourne 
1318b1265b3SPeter Collingbourne   Str.clear();
1328b1265b3SPeter Collingbourne 
1334a5b01ddSStephen Kelly   EXPECT_FALSE(MatchQuery("isMain()", isMain()).run(OS, S));
1348b1265b3SPeter Collingbourne 
1358b1265b3SPeter Collingbourne   EXPECT_EQ("Not a valid top-level matcher.\n", OS.str());
1368b1265b3SPeter Collingbourne }
1371f6066c9SSamuel Benzaquen 
TEST_F(QueryEngineTest,LetAndMatch)1381f6066c9SSamuel Benzaquen TEST_F(QueryEngineTest, LetAndMatch) {
1391f6066c9SSamuel Benzaquen   EXPECT_TRUE(QueryParser::parse("let x \"foo1\"", S)->run(OS, S));
1401f6066c9SSamuel Benzaquen   EXPECT_EQ("", OS.str());
1411f6066c9SSamuel Benzaquen   Str.clear();
1421f6066c9SSamuel Benzaquen 
1431f6066c9SSamuel Benzaquen   EXPECT_TRUE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
1441f6066c9SSamuel Benzaquen   EXPECT_EQ("", OS.str());
1451f6066c9SSamuel Benzaquen   Str.clear();
1461f6066c9SSamuel Benzaquen 
1471f6066c9SSamuel Benzaquen   EXPECT_TRUE(QueryParser::parse("match functionDecl(y)", S)->run(OS, S));
1481f6066c9SSamuel Benzaquen   EXPECT_TRUE(OS.str().find("foo.cc:1:1: note: \"root\" binds here") !=
1491f6066c9SSamuel Benzaquen               std::string::npos);
1501f6066c9SSamuel Benzaquen   EXPECT_TRUE(OS.str().find("1 match.") != std::string::npos);
1511f6066c9SSamuel Benzaquen   Str.clear();
1521f6066c9SSamuel Benzaquen 
1531f6066c9SSamuel Benzaquen   EXPECT_TRUE(QueryParser::parse("unlet x", S)->run(OS, S));
1541f6066c9SSamuel Benzaquen   EXPECT_EQ("", OS.str());
1551f6066c9SSamuel Benzaquen   Str.clear();
1561f6066c9SSamuel Benzaquen 
1571f6066c9SSamuel Benzaquen   EXPECT_FALSE(QueryParser::parse("let y hasName(x)", S)->run(OS, S));
1581f6066c9SSamuel Benzaquen   EXPECT_EQ("1:2: Error parsing argument 1 for matcher hasName.\n"
1591f6066c9SSamuel Benzaquen             "1:10: Value not found: x\n", OS.str());
1601f6066c9SSamuel Benzaquen   Str.clear();
1611f6066c9SSamuel Benzaquen }
162