162 lines · cpp
1//===-- QueryEngineTest.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-exception6//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 21using namespace clang;22using namespace clang::ast_matchers;23using namespace clang::ast_matchers::dynamic;24using namespace clang::query;25using namespace clang::tooling;26 27class 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 35protected: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 50TEST_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 138TEST_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