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 /* AssociatedConstraints */ nullptr);
62
63 cxx_record_decl->setDescribedClassTemplate(class_template_decl);
64 class_template_decl->setInvalidDecl(true);
65
66 return class_template_decl;
67 }
68
69 clang::NamespaceDecl *
CreateNamespaceDecl(const clang::DeclarationName & name,clang::DeclContext * decl_context)70 FakeDeclSource::CreateNamespaceDecl(const clang::DeclarationName &name,
71 clang::DeclContext *decl_context) {
72 clang::NamespaceDecl *namespace_decl = clang::NamespaceDecl::Create(
73 ci_.getASTContext(), decl_context, /* Inline */ false,
74 clang::SourceLocation(), clang::SourceLocation(),
75 name.getAsIdentifierInfo(), /* PrevDecl */ nullptr);
76 namespace_decl->setInvalidDecl(true);
77
78 return namespace_decl;
79 }
80
81 clang::NamedDecl *
CreateDecl(clang::Sema::LookupNameKind kind,const clang::DeclarationNameInfo & name_info,clang::DeclContext * decl_context)82 FakeDeclSource::CreateDecl(clang::Sema::LookupNameKind kind,
83 const clang::DeclarationNameInfo &name_info,
84 clang::DeclContext *decl_context) {
85 const clang::DeclarationName &name = name_info.getName();
86 if (name.getNameKind() != clang::DeclarationName::Identifier) {
87 return nullptr;
88 }
89
90 clang::NamedDecl *decl;
91 switch (kind) {
92 case clang::Sema::LookupOrdinaryName:
93 case clang::Sema::LookupTagName: {
94 clang::CXXRecordDecl *cxx_record_decl =
95 CreateCXXRecordDecl(name, decl_context);
96 // If `<` follows the type name, the type must be a template.
97 // Otherwise, the compiler takes it as a syntax error.
98 const clang::Token &next_token = ci_.getPreprocessor().LookAhead(0);
99 if (next_token.is(clang::tok::less)) {
100 decl = CreateClassTemplateDecl(cxx_record_decl, decl_context);
101 } else {
102 decl = cxx_record_decl;
103 }
104 break;
105 }
106 case clang::Sema::LookupNestedNameSpecifierName:
107 decl = CreateNamespaceDecl(name, decl_context);
108 break;
109 default:
110 decl = nullptr;
111 }
112
113 if (decl) {
114 decl_context->addDecl(decl);
115 }
116 return decl;
117 }
118
119 clang::DeclContext *
ResolveDeclContext(clang::DeclContext * member_context,clang::Scope * scope,clang::NestedNameSpecifier * nns)120 FakeDeclSource::ResolveDeclContext(clang::DeclContext *member_context,
121 clang::Scope *scope,
122 clang::NestedNameSpecifier *nns) {
123 if (member_context) {
124 return member_context;
125 }
126
127 if (nns) {
128 switch (nns->getKind()) {
129 case clang::NestedNameSpecifier::Namespace:
130 return nns->getAsNamespace();
131 case clang::NestedNameSpecifier::NamespaceAlias:
132 return nns->getAsNamespaceAlias()->getNamespace();
133 case clang::NestedNameSpecifier::TypeSpec:
134 case clang::NestedNameSpecifier::TypeSpecWithTemplate:
135 return nns->getAsRecordDecl();
136 case clang::NestedNameSpecifier::Global:
137 return ci_.getASTContext().getTranslationUnitDecl();
138 case clang::NestedNameSpecifier::Identifier:
139 case clang::NestedNameSpecifier::Super:
140 break;
141 }
142 }
143
144 if (scope && scope->getEntity()) {
145 return scope->getEntity();
146 }
147
148 return ci_.getASTContext().getTranslationUnitDecl();
149 }
150
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)151 clang::TypoCorrection FakeDeclSource::CorrectTypo(
152 const clang::DeclarationNameInfo &typo, int lookup_kind,
153 clang::Scope *scope, clang::CXXScopeSpec *scope_spec,
154 clang::CorrectionCandidateCallback &ccc, clang::DeclContext *member_context,
155 bool entering_context, const clang::ObjCObjectPointerType *opt) {
156 // Skip function bodies.
157 if (scope && scope->getFnParent()) {
158 return clang::TypoCorrection();
159 }
160
161 clang::NestedNameSpecifier *nns = nullptr;
162 if (scope_spec && !scope_spec->isEmpty()) {
163 nns = scope_spec->getScopeRep();
164 }
165
166 clang::DeclContext *decl_context =
167 ResolveDeclContext(member_context, scope, nns);
168
169 clang::NamedDecl *decl =
170 CreateDecl(clang::Sema::LookupNameKind(lookup_kind), typo, decl_context);
171 if (decl == nullptr) {
172 return clang::TypoCorrection();
173 }
174
175 return clang::TypoCorrection(decl, nns);
176 }
177
LookupUnqualified(clang::LookupResult & result,clang::Scope * scope)178 bool FakeDeclSource::LookupUnqualified(clang::LookupResult &result,
179 clang::Scope *scope) {
180 // The compiler looks for redeclaration when it parses a known name.
181 if (result.isForRedeclaration()) {
182 return false;
183 }
184 // Skip function bodies.
185 if (scope && scope->getFnParent()) {
186 return false;
187 }
188
189 clang::DeclContext *decl_context;
190 if (scope && scope->getEntity()) {
191 decl_context = scope->getEntity();
192 } else {
193 decl_context = ci_.getASTContext().getTranslationUnitDecl();
194 }
195
196 clang::NamedDecl *decl = CreateDecl(result.getLookupKind(),
197 result.getLookupNameInfo(), decl_context);
198 if (decl == nullptr) {
199 return false;
200 }
201
202 result.addDecl(decl);
203 result.resolveKind();
204 return true;
205 }
206
207
208 } // dumper
209 } // header_checker
210