1 // Copyright 2021 The Dawn Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "dawn_native/CompilationMessages.h" 16 17 #include "common/Assert.h" 18 #include "dawn_native/dawn_platform.h" 19 20 #include <tint/tint.h> 21 22 namespace dawn_native { 23 24 namespace { 25 tintSeverityToMessageType(tint::diag::Severity severity)26 WGPUCompilationMessageType tintSeverityToMessageType(tint::diag::Severity severity) { 27 switch (severity) { 28 case tint::diag::Severity::Note: 29 return WGPUCompilationMessageType_Info; 30 case tint::diag::Severity::Warning: 31 return WGPUCompilationMessageType_Warning; 32 default: 33 return WGPUCompilationMessageType_Error; 34 } 35 } 36 37 } // anonymous namespace 38 OwnedCompilationMessages()39 OwnedCompilationMessages::OwnedCompilationMessages() { 40 mCompilationInfo.nextInChain = 0; 41 mCompilationInfo.messageCount = 0; 42 mCompilationInfo.messages = nullptr; 43 } 44 AddMessageForTesting(std::string message,wgpu::CompilationMessageType type,uint64_t lineNum,uint64_t linePos,uint64_t offset,uint64_t length)45 void OwnedCompilationMessages::AddMessageForTesting(std::string message, 46 wgpu::CompilationMessageType type, 47 uint64_t lineNum, 48 uint64_t linePos, 49 uint64_t offset, 50 uint64_t length) { 51 // Cannot add messages after GetCompilationInfo has been called. 52 ASSERT(mCompilationInfo.messages == nullptr); 53 54 mMessageStrings.push_back(message); 55 mMessages.push_back({nullptr, nullptr, static_cast<WGPUCompilationMessageType>(type), 56 lineNum, linePos, offset, length}); 57 } 58 AddMessage(const tint::diag::Diagnostic & diagnostic)59 void OwnedCompilationMessages::AddMessage(const tint::diag::Diagnostic& diagnostic) { 60 // Cannot add messages after GetCompilationInfo has been called. 61 ASSERT(mCompilationInfo.messages == nullptr); 62 63 // Tint line and column values are 1-based. 64 uint64_t lineNum = diagnostic.source.range.begin.line; 65 uint64_t linePos = diagnostic.source.range.begin.column; 66 // The offset is 0-based. 67 uint64_t offset = 0; 68 uint64_t length = 0; 69 70 if (lineNum && linePos && diagnostic.source.file_content) { 71 const std::vector<std::string>& lines = diagnostic.source.file_content->lines; 72 size_t i = 0; 73 // To find the offset of the message position, loop through each of the first lineNum-1 74 // lines and add it's length (+1 to account for the line break) to the offset. 75 for (; i < lineNum - 1; ++i) { 76 offset += lines[i].length() + 1; 77 } 78 79 // If the end line is on a different line from the beginning line, add the length of the 80 // lines in between to the ending offset. 81 uint64_t endLineNum = diagnostic.source.range.end.line; 82 uint64_t endLinePos = diagnostic.source.range.end.column; 83 uint64_t endOffset = offset; 84 for (; i < endLineNum - 1; ++i) { 85 endOffset += lines[i].length() + 1; 86 } 87 88 // Add the line positions to the offset and endOffset to get their final positions 89 // within the code string. 90 offset += linePos - 1; 91 endOffset += endLinePos - 1; 92 93 // The length of the message is the difference between the starting offset and the 94 // ending offset. 95 length = endOffset - offset; 96 } 97 98 if (diagnostic.code) { 99 mMessageStrings.push_back(std::string(diagnostic.code) + ": " + diagnostic.message); 100 } else { 101 mMessageStrings.push_back(diagnostic.message); 102 } 103 104 mMessages.push_back({nullptr, nullptr, tintSeverityToMessageType(diagnostic.severity), 105 lineNum, linePos, offset, length}); 106 } 107 AddMessages(const tint::diag::List & diagnostics)108 void OwnedCompilationMessages::AddMessages(const tint::diag::List& diagnostics) { 109 // Cannot add messages after GetCompilationInfo has been called. 110 ASSERT(mCompilationInfo.messages == nullptr); 111 112 for (const auto& diag : diagnostics) { 113 AddMessage(diag); 114 } 115 116 AddFormattedTintMessages(diagnostics); 117 } 118 ClearMessages()119 void OwnedCompilationMessages::ClearMessages() { 120 // Cannot clear messages after GetCompilationInfo has been called. 121 ASSERT(mCompilationInfo.messages == nullptr); 122 123 mMessageStrings.clear(); 124 mMessages.clear(); 125 } 126 GetCompilationInfo()127 const WGPUCompilationInfo* OwnedCompilationMessages::GetCompilationInfo() { 128 mCompilationInfo.messageCount = mMessages.size(); 129 mCompilationInfo.messages = mMessages.data(); 130 131 // Ensure every message points at the correct message string. Cannot do this earlier, since 132 // vector reallocations may move the pointers around. 133 for (size_t i = 0; i < mCompilationInfo.messageCount; ++i) { 134 WGPUCompilationMessage& message = mMessages[i]; 135 std::string& messageString = mMessageStrings[i]; 136 message.message = messageString.c_str(); 137 } 138 139 return &mCompilationInfo; 140 } 141 GetFormattedTintMessages()142 const std::vector<std::string>& OwnedCompilationMessages::GetFormattedTintMessages() { 143 return mFormattedTintMessages; 144 } 145 AddFormattedTintMessages(const tint::diag::List & diagnostics)146 void OwnedCompilationMessages::AddFormattedTintMessages(const tint::diag::List& diagnostics) { 147 tint::diag::List messageList; 148 size_t warningCount = 0; 149 size_t errorCount = 0; 150 for (auto& diag : diagnostics) { 151 switch (diag.severity) { 152 case (tint::diag::Severity::Fatal): 153 case (tint::diag::Severity::Error): 154 case (tint::diag::Severity::InternalCompilerError): { 155 errorCount++; 156 messageList.add(tint::diag::Diagnostic(diag)); 157 break; 158 } 159 case (tint::diag::Severity::Warning): { 160 warningCount++; 161 messageList.add(tint::diag::Diagnostic(diag)); 162 break; 163 } 164 default: 165 break; 166 } 167 } 168 if (errorCount == 0 && warningCount == 0) { 169 return; 170 } 171 tint::diag::Formatter::Style style; 172 style.print_newline_at_end = false; 173 std::ostringstream t; 174 if (errorCount > 0) { 175 t << errorCount << " error(s) "; 176 if (warningCount > 0) { 177 t << "and "; 178 } 179 } 180 if (warningCount > 0) { 181 t << warningCount << " warning(s) "; 182 } 183 t << "generated while compiling the shader:" << std::endl 184 << tint::diag::Formatter{style}.format(messageList); 185 mFormattedTintMessages.push_back(t.str()); 186 } 187 188 } // namespace dawn_native 189