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 #ifndef AAPT_DIAGNOSTICS_H 18 #define AAPT_DIAGNOSTICS_H 19 20 #include <iostream> 21 #include <sstream> 22 #include <string> 23 24 #include "android-base/macros.h" 25 #include "androidfw/StringPiece.h" 26 27 #include "Source.h" 28 #include "util/Util.h" 29 30 namespace aapt { 31 32 struct DiagMessageActual { 33 Source source; 34 std::string message; 35 }; 36 37 struct DiagMessage { 38 public: 39 DiagMessage() = default; 40 DiagMessageDiagMessage41 explicit DiagMessage(const android::StringPiece& src) : source_(src) {} 42 DiagMessageDiagMessage43 explicit DiagMessage(const Source& src) : source_(src) {} 44 DiagMessageDiagMessage45 explicit DiagMessage(size_t line) : source_(Source().WithLine(line)) {} 46 47 template <typename T> 48 DiagMessage& operator<<(const T& value) { 49 message_ << value; 50 return *this; 51 } 52 BuildDiagMessage53 DiagMessageActual Build() const { 54 return DiagMessageActual{source_, message_.str()}; 55 } 56 57 private: 58 Source source_; 59 std::stringstream message_; 60 }; 61 62 template <> 63 inline DiagMessage& DiagMessage::operator<<(const ::std::u16string& value) { 64 message_ << android::StringPiece16(value); 65 return *this; 66 } 67 68 struct IDiagnostics { 69 virtual ~IDiagnostics() = default; 70 71 enum class Level { Note, Warn, Error }; 72 73 virtual void Log(Level level, DiagMessageActual& actualMsg) = 0; 74 ErrorIDiagnostics75 virtual void Error(const DiagMessage& message) { 76 DiagMessageActual actual = message.Build(); 77 Log(Level::Error, actual); 78 } 79 WarnIDiagnostics80 virtual void Warn(const DiagMessage& message) { 81 DiagMessageActual actual = message.Build(); 82 Log(Level::Warn, actual); 83 } 84 NoteIDiagnostics85 virtual void Note(const DiagMessage& message) { 86 DiagMessageActual actual = message.Build(); 87 Log(Level::Note, actual); 88 } 89 }; 90 91 class StdErrDiagnostics : public IDiagnostics { 92 public: 93 StdErrDiagnostics() = default; 94 Log(Level level,DiagMessageActual & actual_msg)95 void Log(Level level, DiagMessageActual& actual_msg) override { 96 const char* tag; 97 98 switch (level) { 99 case Level::Error: 100 num_errors_++; 101 if (num_errors_ > 20) { 102 return; 103 } 104 tag = "error"; 105 break; 106 107 case Level::Warn: 108 tag = "warn"; 109 break; 110 111 case Level::Note: 112 tag = "note"; 113 break; 114 } 115 116 if (!actual_msg.source.path.empty()) { 117 std::cerr << actual_msg.source << ": "; 118 } 119 std::cerr << tag << ": " << actual_msg.message << "." << std::endl; 120 } 121 122 private: 123 size_t num_errors_ = 0; 124 125 DISALLOW_COPY_AND_ASSIGN(StdErrDiagnostics); 126 }; 127 128 class SourcePathDiagnostics : public IDiagnostics { 129 public: SourcePathDiagnostics(const Source & src,IDiagnostics * diag)130 SourcePathDiagnostics(const Source& src, IDiagnostics* diag) 131 : source_(src), diag_(diag) {} 132 Log(Level level,DiagMessageActual & actual_msg)133 void Log(Level level, DiagMessageActual& actual_msg) override { 134 actual_msg.source.path = source_.path; 135 diag_->Log(level, actual_msg); 136 if (level == Level::Error) { 137 error = true; 138 } 139 } 140 HadError()141 bool HadError() { 142 return error; 143 } 144 145 private: 146 Source source_; 147 IDiagnostics* diag_; 148 bool error = false; 149 150 DISALLOW_COPY_AND_ASSIGN(SourcePathDiagnostics); 151 }; 152 153 } // namespace aapt 154 155 #endif /* AAPT_DIAGNOSTICS_H */ 156