[AMDGPU][AsmParser][NFC] Translate parsed MIMG instructions to MCInsts automatically.
[llvm-project.git] / clang-tools-extra / include-cleaner / unittests / LocateSymbolTest.cpp
blobd69e25bf8116d27500ecbb199d4d935de5b48516
1 //===--- LocateSymbolTest.cpp -------------------------------------- C++-*-===//
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 #include "AnalysisInternal.h"
9 #include "TypesInternal.h"
10 #include "clang-include-cleaner/Types.h"
11 #include "clang/AST/Decl.h"
12 #include "clang/AST/DeclBase.h"
13 #include "clang/AST/RecursiveASTVisitor.h"
14 #include "clang/Basic/SourceLocation.h"
15 #include "clang/Lex/Preprocessor.h"
16 #include "clang/Testing/TestAST.h"
17 #include "clang/Tooling/Inclusions/StandardLibrary.h"
18 #include "llvm/ADT/StringRef.h"
19 #include "llvm/Support/Casting.h"
20 #include "llvm/Testing/Annotations/Annotations.h"
21 #include "gmock/gmock.h"
22 #include "gtest/gtest.h"
23 #include <tuple>
24 #include <vector>
26 namespace clang::include_cleaner {
27 namespace {
28 using testing::Each;
29 using testing::ElementsAre;
30 using testing::ElementsAreArray;
31 using testing::Eq;
32 using testing::Field;
33 using testing::Pair;
34 using testing::UnorderedElementsAre;
36 // A helper for building ASTs and getting decls out of it by name. Example usage
37 // looks like:
38 // LocateExample X("void ^foo();");
39 // Decl &Foo = X.findDecl("foo");
40 // X.points(); // returns all the points in annotated test input.
41 struct LocateExample {
42 private:
43 llvm::Annotations Target;
44 TestAST AST;
46 public:
47 LocateExample(llvm::StringRef AnnotatedCode)
48 : Target(AnnotatedCode), AST([this] {
49 TestInputs Inputs(Target.code());
50 Inputs.ExtraArgs.push_back("-std=c++17");
51 return Inputs;
52 }()) {}
54 const Decl &findDecl(llvm::StringRef SymbolName) {
55 struct Visitor : RecursiveASTVisitor<Visitor> {
56 llvm::StringRef NameToFind;
57 const NamedDecl *Out = nullptr;
58 bool VisitNamedDecl(const NamedDecl *ND) {
59 // Skip the templated decls, as they have the same name and matches in
60 // this file care about the outer template name.
61 if (auto *TD = ND->getDescribedTemplate())
62 ND = TD;
63 if (ND->getName() == NameToFind) {
64 EXPECT_TRUE(Out == nullptr || Out == ND->getCanonicalDecl())
65 << "Found multiple matches for " << NameToFind.str();
66 Out = llvm::cast<NamedDecl>(ND->getCanonicalDecl());
68 return true;
71 Visitor V;
72 V.NameToFind = SymbolName;
73 V.TraverseDecl(AST.context().getTranslationUnitDecl());
74 if (!V.Out)
75 ADD_FAILURE() << "Couldn't find any decls with name: " << SymbolName;
76 assert(V.Out);
77 return *V.Out;
80 Macro findMacro(llvm::StringRef Name) {
81 auto &PP = AST.preprocessor();
82 auto *II = PP.getIdentifierInfo(Name);
83 if (!II || !II->hasMacroDefinition()) {
84 ADD_FAILURE() << "Couldn't find any macros with name: " << Name;
85 return {};
87 auto MD = PP.getMacroDefinition(II);
88 assert(MD.getMacroInfo());
89 return {II, MD.getMacroInfo()->getDefinitionLoc()};
92 std::vector<SymbolLocation> points() {
93 auto &SM = AST.sourceManager();
94 auto FID = SM.getMainFileID();
95 auto Offsets = Target.points();
96 std::vector<SymbolLocation> Results;
97 for (auto &Offset : Offsets)
98 Results.emplace_back(SM.getComposedLoc(FID, Offset));
99 return Results;
103 TEST(LocateSymbol, Decl) {
104 // Looks for decl with name 'foo' and performs locateSymbol on it.
105 // Expects all the locations in the case to be returned as a location.
106 const llvm::StringLiteral Cases[] = {
107 "struct ^foo; struct ^foo {};",
108 "namespace ns { void ^foo(); void ^foo() {} }",
109 "enum class ^foo; enum class ^foo {};",
112 for (auto &Case : Cases) {
113 SCOPED_TRACE(Case);
114 LocateExample Test(Case);
115 EXPECT_THAT(locateSymbol(Test.findDecl("foo")),
116 ElementsAreArray(Test.points()));
120 TEST(LocateSymbol, Stdlib) {
122 LocateExample Test("namespace std { struct vector; }");
123 EXPECT_THAT(
124 locateSymbol(Test.findDecl("vector")),
125 ElementsAre(*tooling::stdlib::Symbol::named("std::", "vector")));
128 LocateExample Test("#define assert(x)\nvoid foo() { assert(true); }");
129 EXPECT_THAT(locateSymbol(Test.findMacro("assert")),
130 ElementsAre(*tooling::stdlib::Symbol::named("", "assert")));
134 TEST(LocateSymbol, Macros) {
135 // Make sure we preserve the last one.
136 LocateExample Test("#define FOO\n#undef FOO\n#define ^FOO");
137 EXPECT_THAT(locateSymbol(Test.findMacro("FOO")),
138 ElementsAreArray(Test.points()));
141 MATCHER_P2(HintedSymbol, Symbol, Hint, "") {
142 return std::tie(arg.Hint, arg) == std::tie(Hint, Symbol);
144 TEST(LocateSymbol, CompleteSymbolHint) {
146 // stdlib symbols are always complete.
147 LocateExample Test("namespace std { struct vector; }");
148 EXPECT_THAT(locateSymbol(Test.findDecl("vector")),
149 ElementsAre(HintedSymbol(
150 *tooling::stdlib::Symbol::named("std::", "vector"),
151 Hints::CompleteSymbol)));
154 // macros are always complete.
155 LocateExample Test("#define ^FOO");
156 EXPECT_THAT(locateSymbol(Test.findMacro("FOO")),
157 ElementsAre(HintedSymbol(Test.points().front(),
158 Hints::CompleteSymbol)));
161 // Completeness is only absent in cases that matters.
162 const llvm::StringLiteral Cases[] = {
163 "struct ^foo; struct ^foo {};",
164 "template <typename> struct ^foo; template <typename> struct ^foo {};",
165 "template <typename> void ^foo(); template <typename> void ^foo() {};",
167 for (auto &Case : Cases) {
168 SCOPED_TRACE(Case);
169 LocateExample Test(Case);
170 EXPECT_THAT(locateSymbol(Test.findDecl("foo")),
171 ElementsAre(HintedSymbol(Test.points().front(), Hints::None),
172 HintedSymbol(Test.points().back(),
173 Hints::CompleteSymbol)));
177 // All declarations should be marked as complete in cases that a definition
178 // is not usually needed.
179 const llvm::StringLiteral Cases[] = {
180 "void foo(); void foo() {}",
181 "extern int foo; int foo;",
183 for (auto &Case : Cases) {
184 SCOPED_TRACE(Case);
185 LocateExample Test(Case);
186 EXPECT_THAT(locateSymbol(Test.findDecl("foo")),
187 Each(Field(&Hinted<SymbolLocation>::Hint,
188 Eq(Hints::CompleteSymbol))));
193 } // namespace
194 } // namespace clang::include_cleaner