blob: 30deb5555b21669bb38893b7561783ca7c32953c [file] [log] [blame]
Adam Lesinski1ab598f2015-08-14 14:26:04 -07001/*
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#ifndef AAPT_DIAGNOSTICS_H
18#define AAPT_DIAGNOSTICS_H
19
Adam Lesinski1ab598f2015-08-14 14:26:04 -070020#include <iostream>
21#include <sstream>
22#include <string>
23
Adam Lesinskice5e56e2016-10-21 17:56:45 -070024#include "android-base/macros.h"
Adam Lesinskid5083f62017-01-16 15:07:21 -080025#include "androidfw/StringPiece.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070026
27#include "Source.h"
Adam Lesinskice5e56e2016-10-21 17:56:45 -070028#include "util/Util.h"
29
Adam Lesinski1ab598f2015-08-14 14:26:04 -070030namespace aapt {
31
32struct DiagMessageActual {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070033 Source source;
34 std::string message;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070035};
36
37struct DiagMessage {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070038 public:
39 DiagMessage() = default;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070040
Adam Lesinskid5083f62017-01-16 15:07:21 -080041 explicit DiagMessage(const android::StringPiece& src) : source_(src) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070042
Adam Lesinskice5e56e2016-10-21 17:56:45 -070043 explicit DiagMessage(const Source& src) : source_(src) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070044
Adam Lesinskice5e56e2016-10-21 17:56:45 -070045 explicit DiagMessage(size_t line) : source_(Source().WithLine(line)) {}
Adam Lesinskicc5609d2016-04-05 12:41:07 -070046
Adam Lesinskicacb28f2016-10-19 12:18:14 -070047 template <typename T>
48 DiagMessage& operator<<(const T& value) {
Adam Lesinskice5e56e2016-10-21 17:56:45 -070049 message_ << value;
Adam Lesinskicacb28f2016-10-19 12:18:14 -070050 return *this;
51 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070052
Adam Lesinskice5e56e2016-10-21 17:56:45 -070053 DiagMessageActual Build() const {
54 return DiagMessageActual{source_, message_.str()};
Adam Lesinskicacb28f2016-10-19 12:18:14 -070055 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -070056
57 private:
58 Source source_;
59 std::stringstream message_;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070060};
61
Adam Lesinskid5083f62017-01-16 15:07:21 -080062template <>
63inline DiagMessage& DiagMessage::operator<<(const ::std::u16string& value) {
64 message_ << android::StringPiece16(value);
65 return *this;
66}
67
Adam Lesinski1ab598f2015-08-14 14:26:04 -070068struct IDiagnostics {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070069 virtual ~IDiagnostics() = default;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070070
Adam Lesinskicacb28f2016-10-19 12:18:14 -070071 enum class Level { Note, Warn, Error };
Adam Lesinskicc5609d2016-04-05 12:41:07 -070072
Adam Lesinskice5e56e2016-10-21 17:56:45 -070073 virtual void Log(Level level, DiagMessageActual& actualMsg) = 0;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070074
Adam Lesinskice5e56e2016-10-21 17:56:45 -070075 virtual void Error(const DiagMessage& message) {
76 DiagMessageActual actual = message.Build();
77 Log(Level::Error, actual);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070078 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -070079
Adam Lesinskice5e56e2016-10-21 17:56:45 -070080 virtual void Warn(const DiagMessage& message) {
81 DiagMessageActual actual = message.Build();
82 Log(Level::Warn, actual);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070083 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -070084
Adam Lesinskice5e56e2016-10-21 17:56:45 -070085 virtual void Note(const DiagMessage& message) {
86 DiagMessageActual actual = message.Build();
87 Log(Level::Note, actual);
Adam Lesinskicacb28f2016-10-19 12:18:14 -070088 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070089};
90
Adam Lesinskicc5609d2016-04-05 12:41:07 -070091class StdErrDiagnostics : public IDiagnostics {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070092 public:
93 StdErrDiagnostics() = default;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070094
Adam Lesinskice5e56e2016-10-21 17:56:45 -070095 void Log(Level level, DiagMessageActual& actual_msg) override {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070096 const char* tag;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070097
Adam Lesinskicacb28f2016-10-19 12:18:14 -070098 switch (level) {
99 case Level::Error:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700100 num_errors_++;
101 if (num_errors_ > 20) {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700102 return;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700103 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700104 tag = "error";
105 break;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700106
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700107 case Level::Warn:
108 tag = "warn";
109 break;
110
111 case Level::Note:
112 tag = "note";
113 break;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700114 }
115
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700116 if (!actual_msg.source.path.empty()) {
117 std::cerr << actual_msg.source << ": ";
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700118 }
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700119 std::cerr << tag << ": " << actual_msg.message << "." << std::endl;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700120 }
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700121
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700122 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700123 size_t num_errors_ = 0;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700124
125 DISALLOW_COPY_AND_ASSIGN(StdErrDiagnostics);
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700126};
127
128class SourcePathDiagnostics : public IDiagnostics {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700129 public:
130 SourcePathDiagnostics(const Source& src, IDiagnostics* diag)
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700131 : source_(src), diag_(diag) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700132
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700133 void Log(Level level, DiagMessageActual& actual_msg) override {
134 actual_msg.source.path = source_.path;
135 diag_->Log(level, actual_msg);
Ryan Mitchell79848542018-09-11 10:41:09 -0700136 if (level == Level::Error) {
137 error = true;
138 }
139 }
140
141 bool HadError() {
142 return error;
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700143 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700144
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700145 private:
Adam Lesinskice5e56e2016-10-21 17:56:45 -0700146 Source source_;
147 IDiagnostics* diag_;
Ryan Mitchell79848542018-09-11 10:41:09 -0700148 bool error = false;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700149
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700150 DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700151};
152
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700153} // namespace aapt
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700154
155#endif /* AAPT_DIAGNOSTICS_H */