mirror of
https://github.com/openharmony/drivers_framework.git
synced 2026-07-21 11:45:23 -04:00
3e90b3e1df
Signed-off-by: yue <yueyan4@huawei.com>
296 lines
8.9 KiB
C++
296 lines
8.9 KiB
C++
/*
|
|
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
|
*
|
|
* HDF is dual licensed: you can use it either under the terms of
|
|
* the GPL, or the BSD license, at your option.
|
|
* See the LICENSE file in the root of this repository for complete details.
|
|
*/
|
|
|
|
#include "preprocessor/preprocessor.h"
|
|
|
|
#include <algorithm>
|
|
#include <queue>
|
|
|
|
#include "util/file.h"
|
|
#include "util/logger.h"
|
|
#include "util/options.h"
|
|
#include "util/string_builder.h"
|
|
|
|
namespace OHOS {
|
|
namespace HDI {
|
|
String FileDetail::Dump() const
|
|
{
|
|
StringBuilder sb;
|
|
sb.AppendFormat("filePath:%s\n", filePath_.string());
|
|
sb.AppendFormat("fileName:%s\n", fileName_.string());
|
|
sb.AppendFormat("packageName:%s\n", packageName_.string());
|
|
if (imports_.size() == 0) {
|
|
sb.Append("import:[]\n");
|
|
} else {
|
|
sb.Append("import:[\n");
|
|
for (const auto &importStr : imports_) {
|
|
sb.AppendFormat("%s,\n", importStr.string());
|
|
}
|
|
sb.Append("]\n");
|
|
}
|
|
return sb.ToString();
|
|
}
|
|
|
|
bool Preprocessor::Preprocess(std::vector<String> &compileSourceFiles)
|
|
{
|
|
std::vector<String> sourceFiles = Options::GetInstance().GetSourceFiles();
|
|
|
|
// check all path of idl files
|
|
if (!CheckAllFilesPath(sourceFiles)) {
|
|
return false;
|
|
}
|
|
|
|
// analyse impirt infomation of all idl file
|
|
FileDetailMap allFileDetails;
|
|
if (!AnalyseImportInfo(sourceFiles, allFileDetails)) {
|
|
return false;
|
|
}
|
|
|
|
// calculate the order of idl files to compile by counter-topological sorting
|
|
if (!CheckCircularReference(allFileDetails, compileSourceFiles)) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Preprocessor::CheckAllFilesPath(const std::vector<String> &sourceFiles)
|
|
{
|
|
if (sourceFiles.empty()) {
|
|
Logger::E(TAG, "no source files");
|
|
return false;
|
|
}
|
|
|
|
bool ret = true;
|
|
for (const auto &filePath : sourceFiles) {
|
|
if (!File::CheckValid(filePath)) {
|
|
Logger::E(TAG, "invailed file path '%s'.", filePath.string());
|
|
ret = false;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
bool Preprocessor::AnalyseImportInfo(const std::vector<String> &sourceFiles, FileDetailMap &allFileDetails)
|
|
{
|
|
if (sourceFiles.size() == 1) {
|
|
FileDetail info;
|
|
if (!ParseFileDetail(sourceFiles[0], info)) {
|
|
return false;
|
|
}
|
|
|
|
allFileDetails[info.GetFullName()] = info;
|
|
if (!LoadOtherIdlFiles(info, allFileDetails)) {
|
|
return false;
|
|
}
|
|
} else {
|
|
for (const auto &sourceFile : sourceFiles) {
|
|
FileDetail info;
|
|
if (!ParseFileDetail(sourceFile, info)) {
|
|
return false;
|
|
}
|
|
allFileDetails[info.GetFullName()] = info;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Preprocessor::ParseFileDetail(const String &sourceFile, FileDetail &info)
|
|
{
|
|
Lexer lexer;
|
|
if (!lexer.Reset(sourceFile)) {
|
|
Logger::E(TAG, "failed to open file '%s'.", sourceFile.string());
|
|
return false;
|
|
}
|
|
|
|
info.filePath_ = lexer.GetFilePath();
|
|
int startIndex = info.filePath_.LastIndexOf(File::separator);
|
|
int endIndex = info.filePath_.LastIndexOf(".idl");
|
|
if (startIndex == -1 || endIndex == -1 || (startIndex >= endIndex)) {
|
|
Logger::E(TAG, "failed to get file name from '%s'.", info.filePath_.string());
|
|
return false;
|
|
}
|
|
info.fileName_ = info.filePath_.Substring(startIndex + 1, endIndex);
|
|
|
|
if (!ParsePackage(lexer, info)) {
|
|
return false;
|
|
}
|
|
|
|
if (!ParseImports(lexer, info)) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Preprocessor::ParsePackage(Lexer &lexer, FileDetail &info)
|
|
{
|
|
Token token = lexer.PeekToken();
|
|
if (token.kind_ != TokenType::PACKAGE) {
|
|
Logger::E(TAG, "%s: expected 'package' before '%s' token", LocInfo(token).string(), token.value_.string());
|
|
return false;
|
|
}
|
|
lexer.GetToken();
|
|
|
|
token = lexer.PeekToken();
|
|
if (token.kind_ != TokenType::ID) {
|
|
Logger::E(TAG, "%s: expected package name before '%s' token", LocInfo(token).string(), token.value_.string());
|
|
return false;
|
|
}
|
|
info.packageName_ = token.value_;
|
|
lexer.GetToken();
|
|
|
|
token = lexer.PeekToken();
|
|
if (token.kind_ != TokenType::SEMICOLON) {
|
|
Logger::E(TAG, "%s:expected ';' before '%s' token", LocInfo(token).string(), token.value_.string());
|
|
return false;
|
|
}
|
|
lexer.GetToken();
|
|
return true;
|
|
}
|
|
|
|
bool Preprocessor::ParseImports(Lexer &lexer, FileDetail &info)
|
|
{
|
|
Token token = lexer.PeekToken();
|
|
while (token.kind_ != TokenType::END_OF_FILE) {
|
|
if (token.kind_ != TokenType::IMPORT) {
|
|
lexer.GetToken();
|
|
token = lexer.PeekToken();
|
|
continue;
|
|
}
|
|
|
|
lexer.GetToken();
|
|
token = lexer.PeekToken();
|
|
if (token.kind_ != TokenType::ID) {
|
|
Logger::E(
|
|
TAG, "%s: expected import name before '%s' token", LocInfo(token).string(), token.value_.string());
|
|
return false;
|
|
}
|
|
|
|
info.imports_.emplace(token.value_);
|
|
lexer.GetToken();
|
|
|
|
token = lexer.PeekToken();
|
|
if (token.kind_ != TokenType::SEMICOLON) {
|
|
Logger::E(TAG, "%s:expected ';' before '%s' token", LocInfo(token).string(), token.value_.string());
|
|
return false;
|
|
}
|
|
lexer.GetToken();
|
|
|
|
token = lexer.PeekToken();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
bool Preprocessor::LoadOtherIdlFiles(const FileDetail &ownerFileDetail, FileDetailMap &allFileDetails)
|
|
{
|
|
for (const auto &importName : ownerFileDetail.imports_) {
|
|
if (allFileDetails.find(importName) != allFileDetails.end()) {
|
|
continue;
|
|
}
|
|
|
|
String otherFilePath = Options::GetInstance().GetImportFilePath(importName);
|
|
FileDetail otherFileDetail;
|
|
if (!ParseFileDetail(otherFilePath, otherFileDetail)) {
|
|
return false;
|
|
}
|
|
|
|
allFileDetails[otherFileDetail.GetFullName()] = otherFileDetail;
|
|
if (!LoadOtherIdlFiles(otherFileDetail, allFileDetails)) {
|
|
Logger::E(TAG, "failed to load file detail by import '%s'", otherFileDetail.filePath_.string());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Preprocessor::CheckCircularReference(FileDetailMap &allFileDetails, std::vector<String> &compileSourceFiles)
|
|
{
|
|
std::queue<FileDetail> fileQueue;
|
|
for (const auto &filePair : allFileDetails) {
|
|
const FileDetail &file = filePair.second;
|
|
if (file.imports_.size() == 0) {
|
|
fileQueue.push(file);
|
|
}
|
|
}
|
|
|
|
compileSourceFiles.clear();
|
|
while (!fileQueue.empty()) {
|
|
FileDetail curFile = fileQueue.front();
|
|
fileQueue.pop();
|
|
compileSourceFiles.push_back(curFile.filePath_);
|
|
|
|
for (auto &filePair : allFileDetails) {
|
|
FileDetail &otherFile = filePair.second;
|
|
if (otherFile.imports_.empty()) {
|
|
continue;
|
|
}
|
|
|
|
auto position = otherFile.imports_.find(curFile.GetFullName());
|
|
if (position != otherFile.imports_.end()) {
|
|
otherFile.imports_.erase(position);
|
|
}
|
|
|
|
if (otherFile.imports_.size() == 0) {
|
|
fileQueue.push(otherFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (compileSourceFiles.size() == allFileDetails.size()) {
|
|
return true;
|
|
}
|
|
|
|
PrintCyclefInfo(allFileDetails);
|
|
return false;
|
|
}
|
|
|
|
void Preprocessor::PrintCyclefInfo(FileDetailMap &allFileDetails)
|
|
{
|
|
for (FileDetailMap::iterator it = allFileDetails.begin(); it != allFileDetails.end();) {
|
|
if (it->second.imports_.size() == 0) {
|
|
allFileDetails.erase(it++);
|
|
} else {
|
|
it++;
|
|
}
|
|
}
|
|
|
|
for (const auto &filePair : allFileDetails) {
|
|
std::vector<String> traceNodes;
|
|
FindCycle(filePair.second.GetFullName(), allFileDetails, traceNodes);
|
|
}
|
|
}
|
|
|
|
void Preprocessor::FindCycle(const String &curNode, FileDetailMap &allFiles, std::vector<String> &trace)
|
|
{
|
|
auto iter = std::find_if(trace.begin(), trace.end(), [curNode](String name) {
|
|
return name.Equals(curNode);
|
|
});
|
|
if (iter != trace.end()) {
|
|
if (iter == trace.begin()) {
|
|
// print circular reference infomation
|
|
StringBuilder sb;
|
|
for (const auto &nodeName : trace) {
|
|
sb.AppendFormat("%s -> ", nodeName.string());
|
|
}
|
|
sb.AppendFormat("%s", curNode.string());
|
|
Logger::E(TAG, "error: there are circular reference:\n%s", sb.ToString().string());
|
|
}
|
|
return;
|
|
}
|
|
|
|
trace.push_back(curNode);
|
|
for (const auto &importFileName : allFiles[curNode].imports_) {
|
|
FindCycle(importFileName, allFiles, trace);
|
|
}
|
|
|
|
trace.pop_back();
|
|
}
|
|
} // namespace HDI
|
|
} // namespace OHOS
|