1 // Copyright (C) 2018 The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "dumper/fake_decl_source.h"
16
17 #include <clang/Lex/Preprocessor.h>
18 #include <clang/Sema/Lookup.h>
19
20
21 namespace header_checker {
22 namespace dumper {
23
24
FakeDeclSource(const clang::CompilerInstance & ci)25 FakeDeclSource::FakeDeclSource(const clang::CompilerInstance &ci) : ci_(ci) {}
26
27 clang::CXXRecordDecl *
CreateCXXRecordDecl(const clang::DeclarationName & name,clang::DeclContext * decl_context)28 FakeDeclSource::CreateCXXRecordDecl(const clang::DeclarationName &name,
29 clang::DeclContext *decl_context) {
30 clang::CXXRecordDecl *cxx_record_decl = clang::CXXRecordDecl::Create(
31 ci_.getASTContext(), clang::TTK_Struct, decl_context,
32 clang::SourceLocation(), clang::SourceLocation(),
33 name.getAsIdentifierInfo(), /* PrevDecl */ nullptr);
34 cxx_record_decl->setInvalidDecl(true);
35
36 return cxx_record_decl;
37 }
38
39 clang::ClassTemplateDecl *
CreateClassTemplateDecl(clang::CXXRecordDecl * cxx_record_decl,clang::DeclContext * decl_context)40 FakeDeclSource::CreateClassTemplateDecl(clang::CXXRecordDecl *cxx_record_decl,
41 clang::DeclContext *decl_context) {
42 clang::ASTContext &ast = ci_.getASTContext();
43
44 // Declare `template<typename ...T> struct RecordName` in decl_context.
45 clang::TemplateTypeParmDecl *parm = clang::TemplateTypeParmDecl::Create(
46 ast, decl_context, clang::SourceLocation(), clang::SourceLocation(),
47 /* Depth */ 0, /* Position */ 0, /* Id */ nullptr,
48 /* Typename */ true, /* ParameterPack */ true);
49 parm->setInvalidDecl(true);
50
51 clang::NamedDecl *parm_array[1] = {parm};
52 clang::TemplateParameterList *parm_list =
53 clang::TemplateParameterList::Create(
54 ast, clang::SourceLocation(), clang::SourceLocation(), parm_array,
55 clang::SourceLocation(), /* RequiresClause */ nullptr);
56
57 clang::ClassTemplateDecl *class_template_decl =
58 clang::ClassTemplateDecl::Create(
59 ast, decl_context, clang::SourceLocation(),
60 cxx_record_decl->getDeclName(), parm_list, cxx_record_decl);
61
62 cxx_record_decl->setDescribedClassTemplate(class_template_decl);
63 class_template_decl->setInvalidDecl(true);
64
65 return class_template_decl;
66 }
67
68 clang::NamespaceDecl *
CreateNamespaceDecl(const clang::DeclarationName & name,clang::DeclContext * decl_context)69 FakeDeclSource::CreateNamespaceDecl(const clang::DeclarationName &name,
70 clang::DeclContext *decl_context) {
71 clang::NamespaceDecl *namespace_decl = clang::NamespaceDecl::Create(
72 ci_.getASTContext(), decl_context, /* Inline */ false,
73 clang::SourceLocation(), clang::SourceLocation(),
74 name.getAsIdentifierInfo(), /* PrevDecl */ nullptr);
75 namespace_decl->setInvalidDecl(true);
76
77 return namespace_decl;
78 }
79
80 clang::NamedDecl *
CreateDecl(clang::Sema::LookupNameKind kind,const clang::DeclarationNameInfo & name_info,clang::DeclContext * decl_context)81 FakeDeclSource::CreateDecl(clang::Sema::LookupNameKind kind,
82 const clang::DeclarationNameInfo &name_info,
83 clang::DeclContext *decl_context) {
84 const clang::DeclarationName &name = name_info.getName();
85 if (name.getNameKind() != clang::DeclarationName::Identifier) {
86 return nullptr;
87 }
88
89 clang::NamedDecl *decl;
90 switch (kind) {
91 case clang::Sema::LookupOrdinaryName:
92 case clang::Sema::LookupTagName: {
93 clang::CXXRecordDecl *cxx_record_decl =
94 CreateCXXRecordDecl(name, decl_context);
95 // If `<` follows the type name, the type must be a template.
96 // Otherwise, the compiler takes it as a syntax error.
97 const clang::Token &next_token = ci_.getPreprocessor().LookAhead(0);
98 if (next_token.is(clang::tok::less)) {
99 decl = CreateClassTemplateDecl(cxx_record_decl, decl_context);
100 } else {
101 decl = cxx_record_decl;
102 }
103 break;
104 }
105 case clang::Sema::LookupNestedNameSpecifierName:
106 decl = CreateNamespaceDecl(name, decl_context);
107 break;
108 default:
109 decl = nullptr;
110 }
111
112 if (decl) {
113 decl_context->addDecl(decl);
114 }
115 return decl;
116 }
117
118 clang::DeclContext *
ResolveDeclContext(clang::DeclContext * member_context,clang::Scope * scope,clang::NestedNameSpecifier * nns)119 FakeDeclSource::ResolveDeclContext(clang::DeclContext *member_context,
120 clang::Scope *scope,
121 clang::NestedNameSpecifier *nns) {
122 if (member_context) {
123 return member_context;
124 }
125
126 if (nns) {
127 switch (nns->getKind()) {
128 case clang::NestedNameSpecifier::Namespace:
129 return nns->getAsNamespace();
130 case clang::NestedNameSpecifier::NamespaceAlias:
131 return nns->getAsNamespaceAlias()->getNamespace();
132 case clang::NestedNameSpecifier::TypeSpec:
133 case clang::NestedNameSpecifier::TypeSpecWithTemplate:
134 return nns->getAsRecordDecl();
135 case clang::NestedNameSpecifier::Global:
136 return ci_.getASTContext().getTranslationUnitDecl();
137 case clang::NestedNameSpecifier::Identifier:
138 case clang::NestedNameSpecifier::Super:
139 break;
140 }
141 }
142
143 if (scope && scope->getEntity()) {
144 return scope->getEntity();
145 }
146
147 return ci_.getASTContext().getTranslationUnitDecl();
148 }
149
CorrectTypo(const clang::DeclarationNameInfo & typo,int lookup_kind,clang::Scope * scope,clang::CXXScopeSpec * scope_spec,clang::CorrectionCandidateCallback & ccc,clang::DeclContext * member_context,bool entering_context,const clang::ObjCObjectPointerType * opt)150 clang::TypoCorrection FakeDeclSource::CorrectTypo(
151 const clang::DeclarationNameInfo &typo, int lookup_kind,
152 clang::Scope *scope, clang::CXXScopeSpec *scope_spec,
153 clang::CorrectionCandidateCallback &ccc, clang::DeclContext *member_context,
154 bool entering_context, const clang::ObjCObjectPointerType *opt) {
155 // Skip function bodies.
156 if (scope && scope->getFnParent()) {
157 return clang::TypoCorrection();
158 }
159
160 clang::NestedNameSpecifier *nns = nullptr;
161 if (scope_spec && !scope_spec->isEmpty()) {
162 nns = scope_spec->getScopeRep();
163 }
164
165 clang::DeclContext *decl_context =
166 ResolveDeclContext(member_context, scope, nns);
167
168 clang::NamedDecl *decl =
169 CreateDecl(clang::Sema::LookupNameKind(lookup_kind), typo, decl_context);
170 if (decl == nullptr) {
171 return clang::TypoCorrection();
172 }
173
174 return clang::TypoCorrection(decl, nns);
175 }
176
LookupUnqualified(clang::LookupResult & result,clang::Scope * scope)177 bool FakeDeclSource::LookupUnqualified(clang::LookupResult &result,
178 clang::Scope *scope) {
179 // The compiler looks for redeclaration when it parses a known name.
180 if (result.isForRedeclaration()) {
181 return false;
182 }
183 // Skip function bodies.
184 if (scope && scope->getFnParent()) {
185 return false;
186 }
187
188 clang::DeclContext *decl_context;
189 if (scope && scope->getEntity()) {
190 decl_context = scope->getEntity();
191 } else {
192 decl_context = ci_.getASTContext().getTranslationUnitDecl();
193 }
194
195 clang::NamedDecl *decl = CreateDecl(result.getLookupKind(),
196 result.getLookupNameInfo(), decl_context);
197 if (decl == nullptr) {
198 return false;
199 }
200
201 result.addDecl(decl);
202 result.resolveKind();
203 return true;
204 }
205
206
207 } // dumper
208 } // header_checker
209