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