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