1 /*
2 * Copyright (C) 2015, 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 "import_resolver.h"
18 #include "aidl_language.h"
19 #include "logging.h"
20
21 #include <algorithm>
22
23 #include <android-base/file.h>
24 #include <android-base/strings.h>
25 #include <unistd.h>
26
27 #ifdef _WIN32
28 #include <io.h>
29 #endif
30
31 #include "os.h"
32
33 using std::set;
34 using std::string;
35 using std::vector;
36
37 namespace android {
38 namespace aidl {
39
ImportResolver(const IoDelegate & io_delegate,const string & input_file_name,const set<string> & import_paths)40 ImportResolver::ImportResolver(const IoDelegate& io_delegate, const string& input_file_name,
41 const set<string>& import_paths)
42 : io_delegate_(io_delegate), input_file_name_(input_file_name) {
43 for (string path : import_paths) {
44 if (path.empty()) {
45 path = ".";
46 }
47 if (path[path.size() - 1] != OS_PATH_SEPARATOR) {
48 path += OS_PATH_SEPARATOR;
49 }
50 import_paths_.emplace(std::move(path));
51 }
52 }
53
FindImportFile(const string & canonical_name) const54 string ImportResolver::FindImportFile(const string& canonical_name) const {
55 auto parts = base::Split(canonical_name, ".");
56 while (!parts.empty()) {
57 string relative_path = base::Join(parts, OS_PATH_SEPARATOR) + ".aidl";
58 auto candidates = ScanImportPaths(relative_path);
59 if (candidates.size() == 0) {
60 // remove the last part & keep searching
61 parts.pop_back();
62 continue;
63 }
64 if (candidates.size() == 1) {
65 // found! ("legacy" logic: may still be ambiguous path if we try other relative paths)
66 return *candidates.begin();
67 }
68 if (candidates.size() > 1) {
69 AIDL_ERROR(input_file_name_) << "Duplicate files found for " << canonical_name << " from:\n"
70 << base::Join(candidates, "\n");
71 return "";
72 }
73 }
74 AIDL_ERROR(input_file_name_) << "Couldn't find import for class " << canonical_name
75 << ". Searched here:\n - " << base::Join(import_paths_, "\n - ");
76 return "";
77 }
78
ScanImportPaths(const string & relative_path) const79 set<string> ImportResolver::ScanImportPaths(const string& relative_path) const {
80 // Look for that relative path at each of our import roots.
81 set<string> found;
82 for (const auto& path : import_paths_) {
83 if (io_delegate_.FileIsReadable(path + relative_path)) {
84 found.emplace(path + relative_path);
85 }
86 }
87 return found;
88 }
89
90 } // namespace aidl
91 } // namespace android
92