blob: d39cf4c35976800963bfa79fd9a36dac394b432d [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
20#include "Source.h"
Adam Lesinski1ab598f2015-08-14 14:26:04 -070021#include "util/StringPiece.h"
22#include "util/Util.h"
23
Adam Lesinskicc5609d2016-04-05 12:41:07 -070024#include <android-base/macros.h>
Adam Lesinski1ab598f2015-08-14 14:26:04 -070025#include <iostream>
26#include <sstream>
27#include <string>
28
29namespace aapt {
30
31struct DiagMessageActual {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070032 Source source;
33 std::string message;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070034};
35
36struct DiagMessage {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070037 private:
38 Source mSource;
39 std::stringstream mMessage;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070040
Adam Lesinskicacb28f2016-10-19 12:18:14 -070041 public:
42 DiagMessage() = default;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070043
Adam Lesinskicacb28f2016-10-19 12:18:14 -070044 explicit DiagMessage(const StringPiece& src) : mSource(src) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070045
Adam Lesinskicacb28f2016-10-19 12:18:14 -070046 explicit DiagMessage(const Source& src) : mSource(src) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -070047
Adam Lesinskicacb28f2016-10-19 12:18:14 -070048 explicit DiagMessage(size_t line) : mSource(Source().withLine(line)) {}
Adam Lesinskicc5609d2016-04-05 12:41:07 -070049
Adam Lesinskicacb28f2016-10-19 12:18:14 -070050 template <typename T>
51 DiagMessage& operator<<(const T& value) {
52 mMessage << value;
53 return *this;
54 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070055
Adam Lesinskicacb28f2016-10-19 12:18:14 -070056 DiagMessageActual build() const {
57 return DiagMessageActual{mSource, mMessage.str()};
58 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070059};
60
61struct IDiagnostics {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070062 virtual ~IDiagnostics() = default;
Adam Lesinski1ab598f2015-08-14 14:26:04 -070063
Adam Lesinskicacb28f2016-10-19 12:18:14 -070064 enum class Level { Note, Warn, Error };
Adam Lesinskicc5609d2016-04-05 12:41:07 -070065
Adam Lesinskicacb28f2016-10-19 12:18:14 -070066 virtual void log(Level level, DiagMessageActual& actualMsg) = 0;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070067
Adam Lesinskicacb28f2016-10-19 12:18:14 -070068 virtual void error(const DiagMessage& message) {
69 DiagMessageActual actual = message.build();
70 log(Level::Error, actual);
71 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -070072
Adam Lesinskicacb28f2016-10-19 12:18:14 -070073 virtual void warn(const DiagMessage& message) {
74 DiagMessageActual actual = message.build();
75 log(Level::Warn, actual);
76 }
Adam Lesinskicc5609d2016-04-05 12:41:07 -070077
Adam Lesinskicacb28f2016-10-19 12:18:14 -070078 virtual void note(const DiagMessage& message) {
79 DiagMessageActual actual = message.build();
80 log(Level::Note, actual);
81 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -070082};
83
Adam Lesinskicc5609d2016-04-05 12:41:07 -070084class StdErrDiagnostics : public IDiagnostics {
Adam Lesinskicacb28f2016-10-19 12:18:14 -070085 public:
86 StdErrDiagnostics() = default;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070087
Adam Lesinskicacb28f2016-10-19 12:18:14 -070088 void log(Level level, DiagMessageActual& actualMsg) override {
89 const char* tag;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070090
Adam Lesinskicacb28f2016-10-19 12:18:14 -070091 switch (level) {
92 case Level::Error:
93 mNumErrors++;
94 if (mNumErrors > 20) {
95 return;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070096 }
Adam Lesinskicacb28f2016-10-19 12:18:14 -070097 tag = "error";
98 break;
Adam Lesinskicc5609d2016-04-05 12:41:07 -070099
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700100 case Level::Warn:
101 tag = "warn";
102 break;
103
104 case Level::Note:
105 tag = "note";
106 break;
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700107 }
108
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700109 if (!actualMsg.source.path.empty()) {
110 std::cerr << actualMsg.source << ": ";
111 }
112 std::cerr << tag << ": " << actualMsg.message << "." << std::endl;
113 }
Adam Lesinski9ba47d82015-10-13 11:37:10 -0700114
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700115 private:
116 size_t mNumErrors = 0;
117
118 DISALLOW_COPY_AND_ASSIGN(StdErrDiagnostics);
Adam Lesinskicc5609d2016-04-05 12:41:07 -0700119};
120
121class SourcePathDiagnostics : public IDiagnostics {
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700122 public:
123 SourcePathDiagnostics(const Source& src, IDiagnostics* diag)
124 : mSource(src), mDiag(diag) {}
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700125
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700126 void log(Level level, DiagMessageActual& actualMsg) override {
127 actualMsg.source.path = mSource.path;
128 mDiag->log(level, actualMsg);
129 }
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700130
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700131 private:
132 Source mSource;
133 IDiagnostics* mDiag;
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700134
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700135 DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics);
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700136};
137
Adam Lesinskicacb28f2016-10-19 12:18:14 -0700138} // namespace aapt
Adam Lesinski1ab598f2015-08-14 14:26:04 -0700139
140#endif /* AAPT_DIAGNOSTICS_H */