blob: d2fe3624883b47f495cf40b57ba481741ec802a3 [file] [log] [blame]
Jiyong Parke5c45292020-05-26 19:06:24 +09001/*
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"
Steven Moreland21780812020-09-11 01:29:45 +000018#include "aidl_language_y.h"
Jiyong Park2a7c92b2020-07-22 19:12:36 +090019#include "logging.h"
Jiyong Parke5c45292020-05-26 19:06:24 +090020
21void yylex_init(void**);
22void yylex_destroy(void*);
23void yyset_in(FILE* f, void*);
24int yyparse(Parser*);
25YY_BUFFER_STATE yy_scan_buffer(char*, size_t, void*);
26void yy_delete_buffer(YY_BUFFER_STATE, void*);
27
Jooyung Hance6733e2021-05-22 02:44:17 +090028const AidlDocument* Parser::Parse(const std::string& filename,
29 const android::aidl::IoDelegate& io_delegate,
Jooyung Han93f48f02021-06-05 00:11:16 +090030 AidlTypenames& typenames, bool is_preprocessed) {
Jooyung Han397a7602021-06-05 00:06:22 +090031 auto clean_path = android::aidl::IoDelegate::CleanPath(filename);
Jooyung Hance6733e2021-05-22 02:44:17 +090032 // reuse pre-parsed document from typenames
33 for (auto& doc : typenames.AllDocuments()) {
Jooyung Han397a7602021-06-05 00:06:22 +090034 if (doc->GetLocation().GetFile() == clean_path) {
Jooyung Hance6733e2021-05-22 02:44:17 +090035 return doc.get();
36 }
37 }
Jiyong Parke5c45292020-05-26 19:06:24 +090038 // Make sure we can read the file first, before trashing previous state.
Jooyung Han397a7602021-06-05 00:06:22 +090039 unique_ptr<string> raw_buffer = io_delegate.GetFileContents(clean_path);
Jiyong Parke5c45292020-05-26 19:06:24 +090040 if (raw_buffer == nullptr) {
Jooyung Han397a7602021-06-05 00:06:22 +090041 AIDL_ERROR(clean_path) << "Error while opening file for parsing";
Jiyong Parke5c45292020-05-26 19:06:24 +090042 return nullptr;
43 }
44
45 // We're going to scan this buffer in place, and yacc demands we put two
46 // nulls at the end.
47 raw_buffer->append(2u, '\0');
48
Jooyung Han93f48f02021-06-05 00:11:16 +090049 Parser parser(clean_path, *raw_buffer, is_preprocessed);
Jiyong Parke5c45292020-05-26 19:06:24 +090050
Jooyung Hance6733e2021-05-22 02:44:17 +090051 if (yy::parser(&parser).parse() != 0 || parser.HasError()) {
Jiyong Park8e79b7f2020-07-20 20:52:38 +090052 return nullptr;
53 }
Jiyong Parke5c45292020-05-26 19:06:24 +090054
Jooyung Han93f48f02021-06-05 00:11:16 +090055 // transfer ownership to AidlTypenames and return the raw pointer
56 const AidlDocument* result = parser.document_.get();
57 if (!typenames.AddDocument(std::move(parser.document_), is_preprocessed)) {
58 return nullptr;
59 }
60 return result;
Jiyong Parke5c45292020-05-26 19:06:24 +090061}
62
Steven Moreland6c07b832020-10-29 23:39:53 +000063void Parser::SetTypeParameters(AidlTypeSpecifier* type,
64 std::vector<std::unique_ptr<AidlTypeSpecifier>>* type_args) {
65 if (type->IsArray()) {
66 AIDL_ERROR(type) << "Must specify type parameters (<>) before array ([]).";
67 AddError();
68 }
69 if (!type->SetTypeParameters(type_args)) {
70 AIDL_ERROR(type) << "Can only specify one set of type parameters.";
71 AddError();
72 delete type_args;
73 }
74}
75
Jooyung Han93f48f02021-06-05 00:11:16 +090076void Parser::CheckValidTypeName(const AidlToken& token, const AidlLocation& loc) {
77 if (!is_preprocessed_ && token.GetText().find('.') != std::string::npos) {
78 AIDL_ERROR(loc) << "Type name can't be qualified. Use `package`.";
79 AddError();
80 }
81}
82
83void Parser::SetPackage(const AidlPackage& package) {
84 if (is_preprocessed_) {
85 AIDL_ERROR(package) << "Preprocessed file can't declare package.";
86 AddError();
87 }
88 package_ = package.GetName();
89}
90
Jooyung Han289a1bc2021-05-15 15:04:05 +090091class ReferenceResolver : public AidlVisitor {
Jooyung Han29813842020-12-08 01:28:03 +090092 public:
Jooyung Hance6733e2021-05-22 02:44:17 +090093 ReferenceResolver(const AidlDefinedType* scope, TypeResolver& resolver, bool* success)
94 : scope_(scope), resolver_(resolver), success_(success) {}
Jooyung Han289a1bc2021-05-15 15:04:05 +090095
96 void Visit(const AidlTypeSpecifier& t) override {
Jooyung Hanb9d60e02021-05-21 07:54:17 +090097 // We're visiting the same node again. This can happen when two constant references
98 // point to an ancestor of this node.
99 if (t.IsResolved()) {
100 return;
101 }
102
Jooyung Han289a1bc2021-05-15 15:04:05 +0900103 AidlTypeSpecifier& type = const_cast<AidlTypeSpecifier&>(t);
Jooyung Hance6733e2021-05-22 02:44:17 +0900104 if (!resolver_(scope_, &type)) {
Jooyung Han289a1bc2021-05-15 15:04:05 +0900105 AIDL_ERROR(type) << "Failed to resolve '" << type.GetUnresolvedName() << "'";
106 *success_ = false;
107 }
108 }
109
Jooyung Han9d3cbe22020-12-28 03:02:08 +0900110 void Visit(const AidlConstantReference& v) override {
Jooyung Han29813842020-12-08 01:28:03 +0900111 if (IsCircularReference(&v)) {
112 *success_ = false;
113 return;
114 }
115
Jooyung Han9d3cbe22020-12-28 03:02:08 +0900116 const AidlConstantValue* resolved = v.Resolve(scope_);
Jooyung Han29813842020-12-08 01:28:03 +0900117 if (!resolved) {
Jooyung Hane9f5b272021-01-07 00:18:11 +0900118 AIDL_ERROR(v) << "Unknown reference '" << v.Literal() << "'";
Jooyung Han29813842020-12-08 01:28:03 +0900119 *success_ = false;
120 return;
121 }
122
Jooyung Hanb9d60e02021-05-21 07:54:17 +0900123 // On error, skip recursive visiting to avoid redundant messages
124 if (!*success_) {
125 return;
126 }
Jooyung Han29813842020-12-08 01:28:03 +0900127 // resolve recursive references
128 Push(&v);
Jooyung Han289a1bc2021-05-15 15:04:05 +0900129 VisitBottomUp(*this, *resolved);
Jooyung Han29813842020-12-08 01:28:03 +0900130 Pop();
131 }
132
133 private:
134 struct StackElem {
135 const AidlDefinedType* scope;
136 const AidlConstantReference* ref;
137 };
138
139 void Push(const AidlConstantReference* ref) {
140 stack_.push_back({scope_, ref});
Jooyung Han9d3cbe22020-12-28 03:02:08 +0900141 if (ref->GetRefType()) {
142 scope_ = ref->GetRefType()->GetDefinedType();
143 }
Jooyung Han29813842020-12-08 01:28:03 +0900144 }
145
146 void Pop() {
147 scope_ = stack_.back().scope;
148 stack_.pop_back();
149 }
150
151 bool IsCircularReference(const AidlConstantReference* ref) {
152 auto it = std::find_if(stack_.begin(), stack_.end(),
153 [&](const auto& elem) { return elem.ref == ref; });
154 if (it == stack_.end()) {
155 return false;
156 }
157 std::vector<std::string> path;
158 while (it != stack_.end()) {
159 path.push_back(it->ref->Literal());
160 ++it;
161 }
162 path.push_back(ref->Literal());
163 AIDL_ERROR(ref) << "Found a circular reference: " << android::base::Join(path, " -> ");
164 return true;
165 }
166
167 const AidlDefinedType* scope_;
Jooyung Han29813842020-12-08 01:28:03 +0900168 TypeResolver& resolver_;
169 bool* success_;
170 std::vector<StackElem> stack_ = {};
171};
172
Jooyung Han289a1bc2021-05-15 15:04:05 +0900173// Resolve "unresolved" types in the "main" document.
Jooyung Hance6733e2021-05-22 02:44:17 +0900174bool ResolveReferences(const AidlDocument& document, TypeResolver& type_resolver) {
Jiyong Parke5c45292020-05-26 19:06:24 +0900175 bool success = true;
Jooyung Han690f5842020-12-04 13:02:04 +0900176
Jooyung Hance6733e2021-05-22 02:44:17 +0900177 for (const auto& type : document.DefinedTypes()) {
178 ReferenceResolver ref_resolver{type.get(), type_resolver, &success};
Jooyung Han289a1bc2021-05-15 15:04:05 +0900179 VisitBottomUp(ref_resolver, *type);
Jooyung Han690f5842020-12-04 13:02:04 +0900180 }
181
Jiyong Parke5c45292020-05-26 19:06:24 +0900182 return success;
183}
184
Jooyung Han93f48f02021-06-05 00:11:16 +0900185Parser::Parser(const std::string& filename, std::string& raw_buffer, bool is_preprocessed)
186 : filename_(filename), is_preprocessed_(is_preprocessed) {
Jiyong Parke5c45292020-05-26 19:06:24 +0900187 yylex_init(&scanner_);
188 buffer_ = yy_scan_buffer(&raw_buffer[0], raw_buffer.length(), scanner_);
189}
190
191Parser::~Parser() {
192 yy_delete_buffer(buffer_, scanner_);
193 yylex_destroy(scanner_);
194}