• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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