1// Copyright (C) 2020 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "lupdatepreprocessoraction.h"
5#include "filesignificancecheck.h"
6
7#include <clang/Lex/MacroArgs.h>
8#include <clang/Basic/TokenKinds.h>
9
10QT_BEGIN_NAMESPACE
11
12void LupdatePPCallbacks::MacroExpands(const clang::Token &token,
13 const clang::MacroDefinition &macroDefinition, clang::SourceRange sourceRange,
14 const clang::MacroArgs *macroArgs)
15{
16 Q_UNUSED(macroDefinition);
17
18 const auto &sm = m_preprocessor.getSourceManager();
19 llvm::StringRef fileName = sm.getFilename(SpellingLoc: sourceRange.getBegin());
20 if (!LupdatePrivate::isFileSignificant(filePath: fileName.str()))
21 return;
22
23 const QString funcName = QString::fromStdString(s: m_preprocessor.getSpelling(Tok: token));
24 switch (trFunctionAliasManager.trFunctionByName(trFunctionName: funcName)) {
25 default:
26 return;
27 case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS:
28 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP:
29 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3:
30 case TrFunctionAliasManager::Function_QT_TRID_NOOP:
31 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP:
32 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3:
33 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8:
34 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8:
35 case TrFunctionAliasManager::Function_QT_TR_NOOP:
36 case TrFunctionAliasManager::Function_QT_TR_NOOP_UTF8:
37 case TrFunctionAliasManager::Function_QT_TR_N_NOOP:
38 qCDebug(lcClang) << "MacroExpands: Function name:" << funcName;
39 break;
40 }
41
42 TranslationRelatedStore store;
43 store.callType = QStringLiteral("MacroExpands");
44 store.funcName = funcName;
45 store.lupdateLocationFile = toQt(str: fileName);
46 store.lupdateInputFile = toQt(str: m_inputFile);
47 store.lupdateLocationLine = sm.getExpansionLineNumber(Loc: sourceRange.getBegin());
48 store.locationCol = sm.getExpansionColumnNumber(Loc: sourceRange.getBegin());
49
50 if (macroArgs) {
51 std::vector<QString> arguments(macroArgs->getNumMacroArguments());
52 for (unsigned i = 0; i < macroArgs->getNumMacroArguments(); i++) {
53 auto preExpArguments = const_cast<clang::MacroArgs*>(macroArgs)->getPreExpArgument(Arg: i,
54 PP&: m_preprocessor);
55 QString temp;
56 bool errorArgument = false;
57 for (const auto &preExpArgument : preExpArguments) {
58 const auto kind = preExpArgument.getKind();
59 switch (trFunctionAliasManager.trFunctionByName(trFunctionName: funcName)) {
60 default:
61 break;
62 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP:
63 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3:
64 case TrFunctionAliasManager::Function_QT_TRID_NOOP:
65 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP:
66 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3:
67 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8:
68 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8:
69 case TrFunctionAliasManager::Function_QT_TR_NOOP_UTF8:
70 case TrFunctionAliasManager::Function_QT_TR_NOOP:
71 case TrFunctionAliasManager::Function_QT_TR_N_NOOP:
72 if (!clang::tok::isStringLiteral(K: kind))
73 errorArgument = true;
74 break;
75 }
76 if (errorArgument)
77 break;
78 if (clang::tok::isStringLiteral(K: kind))
79 temp += LupdatePrivate::cleanQuote(token: m_preprocessor.getSpelling(Tok: preExpArgument));
80 else
81 temp += QString::fromStdString(s: m_preprocessor.getSpelling(Tok: preExpArgument));
82 }
83 arguments[i] = temp;
84 qCDebug(lcClang) << "*********** macro argument : " << temp;
85 }
86 storeMacroArguments(args: arguments, store: &store);
87 }
88 if (store.isValid())
89 m_ppStores.emplace_back(args: std::move(store));
90}
91
92void LupdatePPCallbacks::storeMacroArguments(const std::vector<QString> &args,
93 TranslationRelatedStore *store)
94{
95 switch (trFunctionAliasManager.trFunctionByName(trFunctionName: store->funcName)) {
96 // only one argument: the context with no "
97 case TrFunctionAliasManager::Function_Q_DECLARE_TR_FUNCTIONS:
98 if (args.size() == 1)
99 store->contextArg = args[0];
100 break;
101 case TrFunctionAliasManager::Function_QT_TR_NOOP_UTF8:
102 case TrFunctionAliasManager::Function_QT_TR_NOOP:
103 case TrFunctionAliasManager::Function_QT_TR_N_NOOP:
104 if (args.size() >= 1)
105 store->lupdateSource = args[0];
106 break;
107 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP:
108 case TrFunctionAliasManager::Function_QT_TRANSLATE_N_NOOP3:
109 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP:
110 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP_UTF8:
111 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3:
112 case TrFunctionAliasManager::Function_QT_TRANSLATE_NOOP3_UTF8:
113 if (args.size() >= 2) {
114 store->contextArg = args[0];
115 store->lupdateSource = args[1];
116 }
117 if (args.size() == 3)
118 store->lupdateComment = args[2];
119 break;
120 // only one argument (?) the message Id
121 case TrFunctionAliasManager::Function_QT_TRID_N_NOOP:
122 case TrFunctionAliasManager::Function_qtTrId:
123 case TrFunctionAliasManager::Function_QT_TRID_NOOP:
124 if (args.size() == 1)
125 store->lupdateId = args[0];
126 break;
127 }
128}
129
130// Hook called when a source range is skipped.
131// Emit a warning if translation information is found within this range.
132void LupdatePPCallbacks::SourceRangeSkipped(clang::SourceRange sourceRange,
133 clang::SourceLocation endifLoc)
134{
135 Q_UNUSED(endifLoc);
136
137 const auto &sm = m_preprocessor.getSourceManager();
138 llvm::StringRef fileName = sm.getFilename(SpellingLoc: sourceRange.getBegin());
139
140 if (!LupdatePrivate::isFileSignificant(filePath: fileName.str()))
141 return;
142
143 const char *begin = sm.getCharacterData(SL: sourceRange.getBegin());
144 const char *end = sm.getCharacterData(SL: sourceRange.getEnd());
145 llvm::StringRef skippedText = llvm::StringRef(begin, end - begin);
146 if (ClangCppParser::stringContainsTranslationInformation(ba: skippedText)) {
147 qCDebug(lcClang) << "SourceRangeSkipped: skipped text:" << QString::fromStdString(s: skippedText.str());
148 unsigned int beginLine = sm.getExpansionLineNumber(Loc: sourceRange.getBegin());
149 unsigned int endLine = sm.getExpansionLineNumber(Loc: sourceRange.getEnd());
150 qWarning(msg: "%s Code with translation information has been skipped "
151 "between lines %d and %d",
152 fileName.str().c_str(), beginLine, endLine);
153 }
154}
155
156// To list the included files
157void LupdatePPCallbacks::InclusionDirective(clang::SourceLocation /*hashLoc*/,
158 const clang::Token & /*includeTok*/, clang::StringRef /*fileName*/, bool /*isAngled*/,
159 clang::CharSourceRange /*filenameRange*/,
160#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(16,0,0))
161 const clang::OptionalFileEntryRef file,
162#elif (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(15,0,0))
163 const clang::Optional<clang::FileEntryRef> file,
164#else
165 const clang::FileEntry *file,
166#endif
167 clang::StringRef /*searchPath*/, clang::StringRef /*relativePath*/,
168 const clang::Module */*imported*/, clang::SrcMgr::CharacteristicKind /*fileType*/)
169{
170 if (!file)
171 return;
172
173 clang::StringRef fileNameRealPath = file->
174#if (LUPDATE_CLANG_VERSION >= LUPDATE_CLANG_VERSION_CHECK(15,0,0))
175 getFileEntry().
176#endif
177 tryGetRealPathName();
178 if (!LupdatePrivate::isFileSignificant(filePath: fileNameRealPath.str()))
179 return;
180
181 TranslationRelatedStore store;
182 store.callType = QStringLiteral("InclusionDirective");
183 store.lupdateLocationFile = toQt(str: fileNameRealPath);
184 store.lupdateLocationLine = 1;
185 store.locationCol = 1;
186 store.lupdateInputFile = toQt(str: m_inputFile);
187 // do not fill the store.funcName. There is no function at this point
188 // the information is retrieved here to look for TRANSLATOR comments in header files
189 // when traversing the AST
190
191 if (store.isValid())
192 m_ppStores.emplace_back(args: std::move(store));
193}
194
195QT_END_NAMESPACE
196

source code of qttools/src/linguist/lupdate/lupdatepreprocessoraction.cpp