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