File indexing completed on 2024-05-19 15:44:53
0001 /* 0002 SPDX-FileCopyrightText: 2014 Kevin Funk <kfunk@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "clangdiagnosticevaluator.h" 0008 #include "unknowndeclarationproblem.h" 0009 #include "missingincludepathproblem.h" 0010 #include "util/clangtypes.h" 0011 0012 namespace 0013 { 0014 0015 /** 0016 * Check whether the problem stated in @p diagnostic may be caused by a missing include 0017 * 0018 * @return True if this may be fixable by adding a include, false otherwise 0019 */ 0020 bool isDeclarationProblem(const QByteArray& description) 0021 { 0022 /* libclang does not currently expose an enum or any other way to query 0023 * what specific semantic error we're dealing with. Instead, we have to 0024 * parse the clang error message and guess if a missing include could be 0025 * the reason for the error 0026 * 0027 * There is no nice way of determining what identifier we're looking at either, 0028 * so we have to read that from the diagnostic too. Hopefully libclang will 0029 * get these features in the future. 0030 * 0031 * I have suggested this feature to clang devs. For reference, see: 0032 * http://lists.cs.uiuc.edu/pipermail/cfe-dev/2014-March/036036.html 0033 */ 0034 0035 return description.startsWith( QByteArrayLiteral("use of undeclared identifier") ) 0036 || description.startsWith( QByteArrayLiteral("no member named") ) 0037 || description.startsWith( QByteArrayLiteral("unknown type name") ) 0038 || description.startsWith( QByteArrayLiteral("variable has incomplete type") ) 0039 || description.startsWith( QByteArrayLiteral("member access into incomplete type") ); 0040 } 0041 0042 /// @return true if @p diagnostic says that include file not found 0043 bool isIncludeFileNotFound(const QByteArray& description) 0044 { 0045 return description.endsWith(QByteArrayLiteral("file not found")); 0046 } 0047 0048 bool isReplaceWithDotProblem(const QByteArray& description) 0049 { 0050 // TODO: The diagnostic message depends on LibClang version. 0051 static const QByteArray diagnosticMessages[] = { 0052 QByteArrayLiteral("did you mean to use '.'?"), 0053 QByteArrayLiteral("maybe you meant to use '.'?") 0054 }; 0055 0056 for (const auto& diagnStr : diagnosticMessages) { 0057 if (description.endsWith(diagnStr)) { 0058 return true; 0059 } 0060 } 0061 0062 return false; 0063 } 0064 0065 bool isReplaceWithArrowProblem(const QByteArray& description) 0066 { 0067 // TODO: The diagnostic message depends on LibClang version. 0068 static const QByteArray diagnosticMessages[] = { 0069 QByteArrayLiteral("did you mean to use '->'?"), 0070 QByteArrayLiteral("maybe you meant to use '->'?") 0071 }; 0072 0073 for (const auto& diagnStr : diagnosticMessages) { 0074 if (description.endsWith(diagnStr)) { 0075 return true; 0076 } 0077 } 0078 0079 return false; 0080 } 0081 0082 } 0083 0084 ClangDiagnosticEvaluator::DiagnosticType ClangDiagnosticEvaluator::diagnosticType(CXDiagnostic diagnostic) 0085 { 0086 const ClangString str(clang_getDiagnosticSpelling(diagnostic)); 0087 const auto description = QByteArray::fromRawData(str.c_str(), qstrlen(str.c_str())); 0088 0089 if (isDeclarationProblem(description)) { 0090 return UnknownDeclarationProblem; 0091 } else if (isIncludeFileNotFound(description)) { 0092 return IncludeFileNotFoundProblem; 0093 } else if (isReplaceWithDotProblem(description)) { 0094 return ReplaceWithDotProblem; 0095 } else if (isReplaceWithArrowProblem(description)) { 0096 return ReplaceWithArrowProblem; 0097 } 0098 0099 return Unknown; 0100 } 0101 0102 ClangProblem* ClangDiagnosticEvaluator::createProblem(CXDiagnostic diagnostic, CXTranslationUnit unit) 0103 { 0104 switch (diagnosticType(diagnostic)) { 0105 case IncludeFileNotFoundProblem: 0106 return new MissingIncludePathProblem(diagnostic, unit); 0107 case UnknownDeclarationProblem: 0108 return new class UnknownDeclarationProblem(diagnostic, unit); 0109 default: 0110 return new ClangProblem(diagnostic, unit); 0111 } 0112 } 0113