• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2019, The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "parser.h"
18 #include "aidl_language_y.h"
19 #include "logging.h"
20 
21 void yylex_init(void**);
22 void yylex_destroy(void*);
23 void yyset_in(FILE* f, void*);
24 int yyparse(Parser*);
25 YY_BUFFER_STATE yy_scan_buffer(char*, size_t, void*);
26 void yy_delete_buffer(YY_BUFFER_STATE, void*);
27 
Parse(const std::string & filename,const android::aidl::IoDelegate & io_delegate,AidlTypenames & typenames)28 std::unique_ptr<Parser> Parser::Parse(const std::string& filename,
29                                       const android::aidl::IoDelegate& io_delegate,
30                                       AidlTypenames& typenames) {
31   // Make sure we can read the file first, before trashing previous state.
32   unique_ptr<string> raw_buffer = io_delegate.GetFileContents(filename);
33   if (raw_buffer == nullptr) {
34     AIDL_ERROR(filename) << "Error while opening file for parsing";
35     return nullptr;
36   }
37 
38   // We're going to scan this buffer in place, and yacc demands we put two
39   // nulls at the end.
40   raw_buffer->append(2u, '\0');
41 
42   std::unique_ptr<Parser> parser(new Parser(filename, *raw_buffer, typenames));
43 
44   if (yy::parser(parser.get()).parse() != 0 || parser->HasError()) {
45     return nullptr;
46   }
47 
48   return parser;
49 }
50 
SetTypeParameters(AidlTypeSpecifier * type,std::vector<std::unique_ptr<AidlTypeSpecifier>> * type_args)51 void Parser::SetTypeParameters(AidlTypeSpecifier* type,
52                                std::vector<std::unique_ptr<AidlTypeSpecifier>>* type_args) {
53   if (type->IsArray()) {
54     AIDL_ERROR(type) << "Must specify type parameters (<>) before array ([]).";
55     AddError();
56   }
57   if (!type->SetTypeParameters(type_args)) {
58     AIDL_ERROR(type) << "Can only specify one set of type parameters.";
59     AddError();
60     delete type_args;
61   }
62 }
63 
64 class ConstantReferenceResolver : public AidlVisitor {
65  public:
ConstantReferenceResolver(const AidlDefinedType * scope,const AidlTypenames & typenames,TypeResolver & resolver,bool * success)66   ConstantReferenceResolver(const AidlDefinedType* scope, const AidlTypenames& typenames,
67                             TypeResolver& resolver, bool* success)
68       : scope_(scope), typenames_(typenames), resolver_(resolver), success_(success) {}
Visit(const AidlConstantReference & v)69   void Visit(const AidlConstantReference& v) override {
70     if (IsCircularReference(&v)) {
71       *success_ = false;
72       return;
73     }
74 
75     if (v.GetRefType() && !v.GetRefType()->IsResolved()) {
76       if (!resolver_(typenames_.GetDocumentFor(scope_), v.GetRefType().get())) {
77         AIDL_ERROR(v.GetRefType()) << "Unknown type '" << v.GetRefType()->GetName() << "'";
78         *success_ = false;
79         return;
80       }
81     }
82     const AidlConstantValue* resolved = v.Resolve(scope_);
83     if (!resolved) {
84       AIDL_ERROR(v) << "Unknown reference '" << v.Literal() << "'";
85       *success_ = false;
86       return;
87     }
88 
89     // resolve recursive references
90     Push(&v);
91     VisitTopDown(*this, *resolved);
92     Pop();
93   }
94 
95  private:
96   struct StackElem {
97     const AidlDefinedType* scope;
98     const AidlConstantReference* ref;
99   };
100 
Push(const AidlConstantReference * ref)101   void Push(const AidlConstantReference* ref) {
102     stack_.push_back({scope_, ref});
103     if (ref->GetRefType()) {
104       scope_ = ref->GetRefType()->GetDefinedType();
105     }
106   }
107 
Pop()108   void Pop() {
109     scope_ = stack_.back().scope;
110     stack_.pop_back();
111   }
112 
IsCircularReference(const AidlConstantReference * ref)113   bool IsCircularReference(const AidlConstantReference* ref) {
114     auto it = std::find_if(stack_.begin(), stack_.end(),
115                            [&](const auto& elem) { return elem.ref == ref; });
116     if (it == stack_.end()) {
117       return false;
118     }
119     std::vector<std::string> path;
120     while (it != stack_.end()) {
121       path.push_back(it->ref->Literal());
122       ++it;
123     }
124     path.push_back(ref->Literal());
125     AIDL_ERROR(ref) << "Found a circular reference: " << android::base::Join(path, " -> ");
126     return true;
127   }
128 
129   const AidlDefinedType* scope_;
130   const AidlTypenames& typenames_;
131   TypeResolver& resolver_;
132   bool* success_;
133   std::vector<StackElem> stack_ = {};
134 };
135 
Resolve(TypeResolver & type_resolver)136 bool Parser::Resolve(TypeResolver& type_resolver) {
137   bool success = true;
138   for (AidlTypeSpecifier* typespec : unresolved_typespecs_) {
139     if (!type_resolver(document_, typespec)) {
140       AIDL_ERROR(typespec) << "Failed to resolve '" << typespec->GetUnresolvedName() << "'";
141       success = false;
142       // don't stop to show more errors if any
143     }
144   }
145 
146   // resolve "field references" as well.
147   for (const auto& type : document_->DefinedTypes()) {
148     ConstantReferenceResolver ref_resolver{type.get(), typenames_, type_resolver, &success};
149     VisitTopDown(ref_resolver, *type);
150   }
151 
152   return success;
153 }
154 
Parser(const std::string & filename,std::string & raw_buffer,android::aidl::AidlTypenames & typenames)155 Parser::Parser(const std::string& filename, std::string& raw_buffer,
156                android::aidl::AidlTypenames& typenames)
157     : filename_(filename), typenames_(typenames) {
158   yylex_init(&scanner_);
159   buffer_ = yy_scan_buffer(&raw_buffer[0], raw_buffer.length(), scanner_);
160 }
161 
~Parser()162 Parser::~Parser() {
163   yy_delete_buffer(buffer_, scanner_);
164   yylex_destroy(scanner_);
165 }
166