in src/checks/manuallevel/qproperty-type-mismatch.cpp [202:308]
void QPropertyTypeMismatch::VisitMacroExpands(const clang::Token &MacroNameTok, const clang::SourceRange &range, const MacroInfo *)
{
IdentifierInfo *ii = MacroNameTok.getIdentifierInfo();
if (!ii) {
return;
}
constexpr llvm::StringLiteral q_property{"Q_PROPERTY"};
if (ii->getName() != q_property) {
return;
}
const CharSourceRange crange = Lexer::getAsCharRange(range, sm(), lo());
llvm::StringRef text = Lexer::getSourceText(crange, sm(), lo());
const auto openingLParen = std::find_if_not(text.begin() + q_property.size(), text.end(), [](char c) {
return std::isspace(c);
});
if (*openingLParen != '(') {
emitWarning(range.getBegin(), "Could not parse argument of the Q_PROPERTY macro");
return;
}
const std::size_t contentBegin = openingLParen - text.begin() + 1;
std::size_t contentLength = text.size() - contentBegin;
if (!text.empty() && text.back() == ')') {
--contentLength;
}
text = text.substr(contentBegin, contentLength);
std::vector<std::string_view> split = clazy::splitStringBySpaces(text);
if (split.size() < 2) {
return;
}
Property p;
p.loc = range.getBegin();
std::size_t splitIndex = 0;
using namespace std::string_view_literals;
// Handle type (type string and any following modifiers)
const auto isModifier = [](std::string_view str) {
return str == "*"sv || str == "&"sv;
};
for (; isModifier(split[splitIndex]) || p.type.empty(); ++splitIndex) {
p.type += split[splitIndex];
}
// Handle name
p.name = split[splitIndex];
std::size_t actualNameStartPos = 0;
// FIXME: This is getting hairy, better use regexps
for (unsigned int i = 0; i < p.name.size(); ++i) {
if (p.name[i] == '*' || p.name[i] == '&') {
p.type += p.name[i];
++actualNameStartPos;
} else {
break;
}
}
if (actualNameStartPos) {
p.name.erase(0, actualNameStartPos);
}
// Handle Q_PROPERTY functions
enum { None, Read, Write, Notify } next = None;
for (const std::string_view &token : split) {
switch (next) {
case None: {
if (token == "READ"sv) {
next = Read;
continue;
} else if (token == "WRITE"sv) {
next = Write;
continue;
} else if (token == "NOTIFY"sv) {
next = Notify;
continue;
} else if (token == "MEMBER"sv) {
p.member = true;
break;
}
break;
}
case Read:
p.read = token;
break;
case Write:
p.write = token;
break;
case Notify:
p.notify = token;
break;
}
next = None;
}
m_qproperties.push_back(std::move(p));
}