File indexing completed on 2024-05-12 04:39:11
0001 /* 0002 SPDX-FileCopyrightText: 2013 Olivier de Gaalon <olivier.jg@gmail.com> 0003 SPDX-FileCopyrightText: 2015 Milian Wolff <mail@milianw.de> 0004 0005 SPDX-License-Identifier: LGPL-2.0-or-later 0006 */ 0007 0008 #include "builder.h" 0009 0010 #include "util/clangdebug.h" 0011 0012 #include "templatehelpers.h" 0013 #include "cursorkindtraits.h" 0014 #include "clangducontext.h" 0015 #include "macrodefinition.h" 0016 #include "types/classspecializationtype.h" 0017 #include "util/clangutils.h" 0018 #include "util/clangtypes.h" 0019 0020 #include <util/pushvalue.h> 0021 0022 #include <language/duchain/duchainlock.h> 0023 #include <language/duchain/classdeclaration.h> 0024 #include <language/duchain/stringhelpers.h> 0025 #include <language/duchain/duchainutils.h> 0026 #include <language/duchain/problem.h> 0027 0028 #include <language/duchain/types/pointertype.h> 0029 #include <language/duchain/types/arraytype.h> 0030 #include <language/duchain/types/referencetype.h> 0031 #include <language/duchain/types/functiontype.h> 0032 #include <language/duchain/types/structuretype.h> 0033 #include <language/duchain/types/enumerationtype.h> 0034 #include <language/duchain/types/enumeratortype.h> 0035 #include <language/duchain/types/typealiastype.h> 0036 #include <language/duchain/types/indexedtype.h> 0037 0038 #include <clang-c/Documentation.h> 0039 0040 #include <QVarLengthArray> 0041 0042 #include <algorithm> 0043 #include <unordered_map> 0044 #include <typeinfo> 0045 0046 0047 /// Turn on for debugging the declaration building 0048 #define IF_DEBUG(x) 0049 0050 using namespace KDevelop; 0051 0052 namespace { 0053 0054 #if CINDEX_VERSION_MINOR >= 100 0055 // TODO: this is ugly, can we find a better alternative? 0056 bool jsonTestRun() 0057 { 0058 static bool runningTest = qEnvironmentVariableIsSet("KDEV_CLANG_JSON_TEST_RUN"); 0059 return runningTest; 0060 } 0061 #endif 0062 0063 //BEGIN helpers 0064 // HACK: current alias type template machinery is badly broken wrt spelling 0065 // location, work around this by adjusting all references to point to child 0066 // type alias node with proper location 0067 // TODO: investigate upstream implementation of CXCursor_TypeAliasTemplateDecl 0068 CXCursor findEmbeddedTypeAlias(CXCursor aliasTemplate) 0069 { 0070 auto result = clang_getNullCursor(); 0071 clang_visitChildren(aliasTemplate, [] (CXCursor cursor, CXCursor, CXClientData data) { 0072 if (clang_getCursorKind(cursor) == CXCursor_TypeAliasDecl) { 0073 auto res = reinterpret_cast<CXCursor*>(data); 0074 *res = cursor; 0075 return CXChildVisit_Break; 0076 } 0077 return CXChildVisit_Continue; 0078 }, &result); 0079 return result; 0080 } 0081 0082 /** 0083 * Find the cursor that cursor @p cursor references 0084 * 0085 * First tries to get the referenced cursor via clang_getCursorReferenced, 0086 * and if that fails, tries to get them via clang_getOverloadedDecl 0087 * (which returns the referenced cursor for CXCursor_OverloadedDeclRef, for example) 0088 * 0089 * @return Valid cursor on success, else null cursor 0090 */ 0091 CXCursor referencedCursor(CXCursor cursor) 0092 { 0093 auto referenced = clang_getCursorReferenced(cursor); 0094 // HACK: see notes at getEmbeddedTypeAlias() 0095 if (clang_getCursorKind(referenced) == CXCursor_TypeAliasTemplateDecl) { 0096 return findEmbeddedTypeAlias(referenced); 0097 } 0098 0099 if (!clang_equalCursors(cursor, referenced)) { 0100 return referenced; 0101 } 0102 0103 // get the first result for now 0104 referenced = clang_getOverloadedDecl(cursor, 0); 0105 if (!clang_Cursor_isNull(referenced)) { 0106 return referenced; 0107 } 0108 return clang_getNullCursor(); 0109 } 0110 0111 Identifier makeId(CXCursor cursor) 0112 { 0113 if (CursorKindTraits::isClassTemplate(cursor.kind)) { 0114 // TODO: how to handle functions here? We don't want to add the "real" function arguments here 0115 // and there does not seem to be an API to get the template arguments for non-specializations easily 0116 // NOTE: using the QString overload of the Identifier ctor here, so that the template name gets parsed 0117 return Identifier(ClangString(clang_getCursorDisplayName(cursor)).toString()); 0118 } 0119 0120 const ClangString spelling(clang_getCursorSpelling(cursor)); 0121 if (!spelling.isEmpty() && spelling.c_str()[0] == '[') { 0122 // skip unexposed DecompositionDecl, we want to get hold of the BindingsDecl inside instead 0123 return Identifier(); 0124 } 0125 0126 auto name = spelling.toIndexed(); 0127 if (name.isEmpty() && CursorKindTraits::isClass(cursor.kind)) { 0128 // try to use the type name for typedef'ed anon structs etc. as a fallback 0129 auto type = ClangString(clang_getTypeSpelling(clang_getCursorType(cursor))).toString(); 0130 // but don't associate a super long name for anon structs without a typedef 0131 if (!type.startsWith(QLatin1String("(anonymous "))) { 0132 name = IndexedString(type); 0133 } 0134 } 0135 0136 return Identifier(name); 0137 } 0138 0139 #if CINDEX_VERSION_MINOR >= 100 // FIXME https://bugs.llvm.org/show_bug.cgi?id=35333 0140 QByteArray makeComment(CXComment comment) 0141 { 0142 if (Q_UNLIKELY(jsonTestRun())) { 0143 auto kind = clang_Comment_getKind(comment); 0144 if (kind == CXComment_Text) 0145 return ClangString(clang_TextComment_getText(comment)).toByteArray(); 0146 0147 QByteArray text; 0148 int numChildren = clang_Comment_getNumChildren(comment); 0149 for (int i = 0; i < numChildren; ++i) 0150 text += makeComment(clang_Comment_getChild(comment, i)); 0151 return text; 0152 } 0153 0154 return ClangString(clang_FullComment_getAsHTML(comment)).toByteArray(); 0155 } 0156 #endif 0157 0158 AbstractType* createDelayedType(CXType type) 0159 { 0160 auto t = new DelayedType; 0161 0162 QString typeName = ClangString(clang_getTypeSpelling(type)).toString(); 0163 typeName.remove(QStringLiteral("const ")); 0164 typeName.remove(QStringLiteral("volatile ")); 0165 0166 t->setIdentifier(IndexedTypeIdentifier(typeName)); 0167 return t; 0168 } 0169 0170 void contextImportDecl(DUContext* context, const DeclarationPointer& decl) 0171 { 0172 auto top = context->topContext(); 0173 if (auto import = decl->logicalInternalContext(top)) { 0174 context->addImportedParentContext(import); 0175 context->topContext()->updateImportsCache(); 0176 } 0177 } 0178 0179 //END helpers 0180 0181 CXChildVisitResult visitCursor(CXCursor cursor, CXCursor parent, CXClientData data); 0182 0183 //BEGIN IdType 0184 template<CXCursorKind CK, class Enable = void> 0185 struct IdType; 0186 0187 template<CXCursorKind CK> 0188 struct IdType<CK, typename std::enable_if<CursorKindTraits::isClass(CK)>::type> 0189 { 0190 using Type = StructureType; 0191 }; 0192 0193 template<CXCursorKind CK> 0194 struct IdType<CK, typename std::enable_if<CK == CXCursor_TypedefDecl>::type> 0195 { 0196 using Type = TypeAliasType; 0197 }; 0198 0199 template<CXCursorKind CK> 0200 struct IdType<CK, typename std::enable_if<CK == CXCursor_TypeAliasDecl>::type> 0201 { 0202 using Type = TypeAliasType; 0203 }; 0204 0205 template<CXCursorKind CK> 0206 struct IdType<CK, typename std::enable_if<CK == CXCursor_EnumDecl>::type> 0207 { 0208 using Type = EnumerationType; 0209 }; 0210 0211 template<CXCursorKind CK> 0212 struct IdType<CK, typename std::enable_if<CK == CXCursor_EnumConstantDecl>::type> 0213 { 0214 using Type = EnumeratorType; 0215 }; 0216 //END IdType 0217 0218 //BEGIN DeclType 0219 template<CXCursorKind CK, bool isDefinition, bool isClassMember, class Enable = void> 0220 struct DeclType; 0221 0222 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0223 struct DeclType<CK, isDefinition, isInClass, 0224 typename std::enable_if<CursorKindTraits::isKDevDeclaration(CK, isInClass)>::type> 0225 { 0226 using Type = Declaration; 0227 }; 0228 0229 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0230 struct DeclType<CK, isDefinition, isInClass, 0231 typename std::enable_if<CK == CXCursor_MacroDefinition>::type> 0232 { 0233 using Type = MacroDefinition; 0234 }; 0235 0236 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0237 struct DeclType<CK, isDefinition, isInClass, 0238 typename std::enable_if<CursorKindTraits::isKDevForwardDeclaration(CK, isDefinition)>::type> 0239 { 0240 using Type = ForwardDeclaration; 0241 }; 0242 0243 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0244 struct DeclType<CK, isDefinition, isInClass, 0245 typename std::enable_if<CursorKindTraits::isKDevClassDeclaration(CK, isDefinition)>::type> 0246 { 0247 using Type = ClassDeclaration; 0248 }; 0249 0250 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0251 struct DeclType<CK, isDefinition, isInClass, 0252 typename std::enable_if<CursorKindTraits::isKDevClassFunctionDeclaration(CK, isInClass)>::type> 0253 { 0254 using Type = ClassFunctionDeclaration; 0255 }; 0256 0257 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0258 struct DeclType<CK, isDefinition, isInClass, 0259 typename std::enable_if<CursorKindTraits::isKDevFunctionDeclaration(CK, isDefinition, isInClass)>::type> 0260 { 0261 using Type = FunctionDeclaration; 0262 }; 0263 0264 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0265 struct DeclType<CK, isDefinition, isInClass, 0266 typename std::enable_if<CursorKindTraits::isKDevFunctionDefinition(CK, isDefinition, isInClass)>::type> 0267 { 0268 using Type = FunctionDefinition; 0269 }; 0270 0271 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0272 struct DeclType<CK, isDefinition, isInClass, 0273 typename std::enable_if<CursorKindTraits::isKDevNamespaceAliasDeclaration(CK, isDefinition)>::type> 0274 { 0275 using Type = NamespaceAliasDeclaration; 0276 }; 0277 0278 template<CXCursorKind CK, bool isDefinition, bool isInClass> 0279 struct DeclType<CK, isDefinition, isInClass, 0280 typename std::enable_if<CursorKindTraits::isKDevClassMemberDeclaration(CK, isInClass)>::type> 0281 { 0282 using Type = ClassMemberDeclaration; 0283 }; 0284 //END DeclType 0285 0286 //BEGIN CurrentContext 0287 struct CurrentContext 0288 { 0289 CurrentContext(DUContext* context, const QSet<DUContext*>& keepAliveContexts) 0290 : context(context) 0291 , keepAliveContexts(keepAliveContexts) 0292 { 0293 DUChainReadLocker lock; 0294 previousChildContexts = context->childContexts(); 0295 previousChildDeclarations = context->localDeclarations(); 0296 } 0297 0298 ~CurrentContext() 0299 { 0300 DUChainWriteLocker lock; 0301 for (auto* childContext : qAsConst(previousChildContexts)) { 0302 if (!keepAliveContexts.contains(childContext)) { 0303 delete childContext; 0304 } 0305 } 0306 qDeleteAll(previousChildDeclarations); 0307 if (resortChildContexts) { 0308 context->resortChildContexts(); 0309 } 0310 if (resortLocalDeclarations) { 0311 context->resortLocalDeclarations(); 0312 } 0313 } 0314 0315 DUContext* context; 0316 // when updating, this contains child contexts of the current parent context 0317 QVector<DUContext*> previousChildContexts; 0318 // when updating, this contains contexts that must not be deleted 0319 QSet<DUContext*> keepAliveContexts; 0320 // when updating, this contains child declarations of the current parent context 0321 QVector<Declaration*> previousChildDeclarations; 0322 0323 bool resortChildContexts = false; 0324 bool resortLocalDeclarations = false; 0325 }; 0326 //END CurrentContext 0327 0328 //BEGIN Visitor 0329 struct Visitor 0330 { 0331 explicit Visitor(CXTranslationUnit tu, CXFile file, 0332 const IncludeFileContexts& includes, const bool update); 0333 0334 AbstractType *makeType(CXType type, CXCursor parent); 0335 AbstractType::Ptr makeAbsType(CXType type, CXCursor parent) 0336 { 0337 return AbstractType::Ptr(makeType(type, parent)); 0338 } 0339 0340 //BEGIN dispatch* 0341 template<CXCursorKind CK, 0342 Decision IsInClass = CursorKindTraits::isInClass(CK), 0343 EnableIf<IsInClass == Decision::Maybe> = dummy> 0344 CXChildVisitResult dispatchCursor(CXCursor cursor, CXCursor parent); 0345 0346 template<CXCursorKind CK, 0347 Decision IsInClass = CursorKindTraits::isInClass(CK), 0348 Decision IsDefinition = CursorKindTraits::isDefinition(CK), 0349 EnableIf<IsDefinition == Decision::Maybe && IsInClass != Decision::Maybe> = dummy> 0350 CXChildVisitResult dispatchCursor(CXCursor cursor, CXCursor parent); 0351 0352 template<CXCursorKind CK, 0353 Decision IsInClass = CursorKindTraits::isInClass(CK), 0354 Decision IsDefinition = CursorKindTraits::isDefinition(CK), 0355 EnableIf<IsInClass != Decision::Maybe && IsDefinition != Decision::Maybe> = dummy> 0356 CXChildVisitResult dispatchCursor(CXCursor cursor, CXCursor parent); 0357 0358 CXChildVisitResult dispatchTypeAliasTemplate(CXCursor cursor, CXCursor parent) 0359 { 0360 return CursorKindTraits::isClass(clang_getCursorKind(parent)) ? buildTypeAliasTemplateDecl<true>(cursor) 0361 : buildTypeAliasTemplateDecl<false>(cursor); 0362 } 0363 0364 template<CXTypeKind TK> 0365 AbstractType *dispatchType(CXType type, CXCursor cursor) 0366 { 0367 IF_DEBUG(clangDebug() << "TK:" << type.kind;) 0368 0369 auto kdevType = createType<TK>(type, cursor); 0370 if (kdevType) { 0371 setTypeModifiers<TK>(type, kdevType); 0372 setTypeSize(type, kdevType); 0373 } 0374 return kdevType; 0375 } 0376 //BEGIN dispatch* 0377 0378 //BEGIN build* 0379 template<CXCursorKind CK, class DeclType, bool hasContext> 0380 CXChildVisitResult buildDeclaration(CXCursor cursor); 0381 0382 template<bool IsInClass> 0383 CXChildVisitResult buildTypeAliasTemplateDecl(CXCursor cursor); 0384 0385 CXChildVisitResult buildUse(CXCursor cursor); 0386 CXChildVisitResult buildMacroExpansion(CXCursor cursor); 0387 0388 template<CXCursorKind CK> 0389 CXChildVisitResult buildCompoundStatement(CXCursor cursor); 0390 CXChildVisitResult buildCXXBaseSpecifier(CXCursor cursor); 0391 CXChildVisitResult buildParmDecl(CXCursor cursor); 0392 0393 //END build* 0394 0395 //BEGIN create* 0396 template<CXCursorKind CK, class DeclType> 0397 DeclType* createDeclarationCommon(CXCursor cursor, const Identifier& id) 0398 { 0399 auto range = ClangHelpers::cursorSpellingNameRange(cursor, id); 0400 0401 if (id.isEmpty()) { 0402 // This is either an anonymous function parameter e.g.: void f(int); 0403 // Or anonymous struct/class/union e.g.: struct {} anonymous; 0404 // Set empty range for it 0405 range.end = range.start; 0406 } 0407 0408 // check if cursor is inside a macro expansion 0409 auto clangRange = clang_Cursor_getSpellingNameRange(cursor, 0, 0); 0410 unsigned int expansionLocOffset; 0411 const auto spellingLocation = clang_getRangeStart(clangRange); 0412 clang_getExpansionLocation(spellingLocation, nullptr, nullptr, nullptr, &expansionLocOffset); 0413 if (m_macroExpansionLocations.contains(expansionLocOffset)) { 0414 unsigned int spellingLocOffset; 0415 clang_getSpellingLocation(spellingLocation, nullptr, nullptr, nullptr, &spellingLocOffset); 0416 // Set empty ranges for declarations inside macro expansion 0417 if (spellingLocOffset == expansionLocOffset) { 0418 range.end = range.start; 0419 } 0420 } 0421 0422 if (m_update) { 0423 const IndexedIdentifier indexedId(id); 0424 DUChainWriteLocker lock; 0425 auto it = m_parentContext->previousChildDeclarations.begin(); 0426 while (it != m_parentContext->previousChildDeclarations.end()) { 0427 auto decl = dynamic_cast<DeclType*>(*it); 0428 if (decl && decl->indexedIdentifier() == indexedId) { 0429 decl->setRange(range); 0430 m_parentContext->resortLocalDeclarations = true; 0431 setDeclData<CK>(cursor, decl); 0432 m_cursorToDeclarationCache[cursor] = decl; 0433 m_parentContext->previousChildDeclarations.erase(it); 0434 return decl; 0435 } 0436 ++it; 0437 } 0438 } 0439 auto decl = new DeclType(range, nullptr); 0440 decl->setIdentifier(id); 0441 #if CINDEX_VERSION_MINOR >= 32 0442 decl->setExplicitlyTyped(clang_getCursorType(cursor).kind != CXType_Auto); 0443 #endif 0444 m_cursorToDeclarationCache[cursor] = decl; 0445 setDeclData<CK>(cursor, decl); 0446 { 0447 DUChainWriteLocker lock; 0448 decl->setContext(m_parentContext->context); 0449 } 0450 return decl; 0451 } 0452 0453 template<CXCursorKind CK, class DeclType> 0454 Declaration* createDeclaration(CXCursor cursor, const Identifier& id, DUContext *context) 0455 { 0456 auto decl = createDeclarationCommon<CK, DeclType>(cursor, id); 0457 auto type = createType<CK>(cursor); 0458 if (type) { 0459 setTypeSize(clang_getCursorType(cursor), type); 0460 } 0461 0462 DUChainWriteLocker lock; 0463 if (context) 0464 decl->setInternalContext(context); 0465 setDeclType<CK>(decl, type); 0466 setDeclInCtxtData<CK>(cursor, decl); 0467 return decl; 0468 } 0469 0470 template<CXCursorKind CK, DUContext::ContextType Type> 0471 DUContext* createContext(CXCursor cursor, const QualifiedIdentifier& scopeId = {}) 0472 { 0473 // wtf: why is the DUContext API requesting a QID when it needs a plain Id?! 0474 // see: testNamespace 0475 auto range = ClangRange(clang_getCursorExtent(cursor)).toRangeInRevision(); 0476 DUChainWriteLocker lock; 0477 if (m_update) { 0478 const IndexedQualifiedIdentifier indexedScopeId(scopeId); 0479 auto it = m_parentContext->previousChildContexts.begin(); 0480 while (it != m_parentContext->previousChildContexts.end()) { 0481 auto ctx = *it; 0482 if (ctx->type() == Type && ctx->indexedLocalScopeIdentifier() == indexedScopeId) { 0483 ctx->setRange(range); 0484 m_parentContext->resortChildContexts = true; 0485 m_parentContext->previousChildContexts.erase(it); 0486 return ctx; 0487 } 0488 ++it; 0489 } 0490 } 0491 //TODO: (..type, id..) constructor for DUContext? 0492 auto context = new ClangNormalDUContext(range, m_parentContext->context); 0493 context->setType(Type); 0494 context->setLocalScopeIdentifier(scopeId); 0495 if (Type == DUContext::Other || Type == DUContext::Function) 0496 context->setInSymbolTable(false); 0497 0498 if (CK == CXCursor_CXXMethod) { 0499 CXCursor semParent = clang_getCursorSemanticParent(cursor); 0500 // only import the semantic parent if it differs from the lexical parent 0501 if (!clang_Cursor_isNull(semParent) && !clang_equalCursors(semParent, clang_getCursorLexicalParent(cursor))) { 0502 auto semParentDecl = findDeclaration(semParent); 0503 if (semParentDecl) { 0504 contextImportDecl(context, semParentDecl); 0505 } 0506 } 0507 } 0508 return context; 0509 } 0510 0511 template<CXTypeKind TK, EnableIf<CursorKindTraits::integralType(TK) != IntegralType::TypeNotIntegralType> = dummy> 0512 AbstractType *createType(CXType, CXCursor) 0513 { 0514 // TODO: would be nice to instantiate a ConstantIntegralType here and set a value if possible 0515 // but unfortunately libclang doesn't offer API to that 0516 // also see https://marc.info/?l=cfe-commits&m=131609142917881&w=2 0517 return new IntegralType(CursorKindTraits::integralType(TK)); 0518 } 0519 0520 template <CXTypeKind TK, EnableIf<CursorKindTraits::isOpenCLType(TK)> = dummy> 0521 AbstractType* createType(CXType, CXCursor) 0522 { 0523 return new StructureType(); 0524 } 0525 0526 #if CINDEX_VERSION_MINOR >= 60 0527 template <CXTypeKind TK, EnableIf<TK == CXType_Atomic> = dummy> 0528 AbstractType* createType(CXType type, CXCursor parent) 0529 { 0530 // Decompose the atomic type. 0531 return makeType(clang_Type_getValueType(type), parent); 0532 } 0533 #endif 0534 0535 template<CXTypeKind TK, EnableIf<CursorKindTraits::isPointerType(TK)> = dummy> 0536 AbstractType *createType(CXType type, CXCursor parent) 0537 { 0538 auto ptr = new PointerType; 0539 ptr->setBaseType(makeAbsType(clang_getPointeeType(type), parent)); 0540 return ptr; 0541 } 0542 0543 template<CXTypeKind TK, EnableIf<CursorKindTraits::isArrayType(TK)> = dummy> 0544 AbstractType *createType(CXType type, CXCursor parent) 0545 { 0546 auto arr = new ArrayType; 0547 arr->setDimension((TK == CXType_IncompleteArray || TK == CXType_VariableArray || TK == CXType_DependentSizedArray) ? 0 : clang_getArraySize(type)); 0548 arr->setElementType(makeAbsType(clang_getArrayElementType(type), parent)); 0549 return arr; 0550 } 0551 0552 template<CXTypeKind TK, EnableIf<TK == CXType_RValueReference || TK == CXType_LValueReference> = dummy> 0553 AbstractType *createType(CXType type, CXCursor parent) 0554 { 0555 auto ref = new ReferenceType; 0556 ref->setIsRValue(type.kind == CXType_RValueReference); 0557 ref->setBaseType(makeAbsType(clang_getPointeeType(type), parent)); 0558 return ref; 0559 } 0560 0561 template<CXTypeKind TK, EnableIf<TK == CXType_FunctionProto || TK == CXType_FunctionNoProto> = dummy> 0562 AbstractType *createType(CXType type, CXCursor parent) 0563 { 0564 auto func = new FunctionType; 0565 func->setReturnType(makeAbsType(clang_getResultType(type), parent)); 0566 const int numArgs = clang_getNumArgTypes(type); 0567 for (int i = 0; i < numArgs; ++i) { 0568 func->addArgument(makeAbsType(clang_getArgType(type, i), parent)); 0569 } 0570 0571 if (clang_isFunctionTypeVariadic(type)) { 0572 auto type = new DelayedType; 0573 static const auto id = IndexedTypeIdentifier(QStringLiteral("...")); 0574 type->setIdentifier(id); 0575 type->setKind(DelayedType::Unresolved); 0576 func->addArgument(AbstractType::Ptr(type)); 0577 } 0578 0579 return func; 0580 } 0581 0582 template<CXTypeKind TK, EnableIf<TK == CXType_Record || TK == CXType_ObjCInterface || TK == CXType_ObjCClass> = dummy> 0583 AbstractType *createType(CXType type, CXCursor parent) 0584 { 0585 DeclarationPointer decl = findDeclaration(clang_getTypeDeclaration(type)); 0586 DUChainReadLocker lock; 0587 0588 if (!decl) { 0589 // probably a forward-declared type 0590 decl = ClangHelpers::findForwardDeclaration(type, m_parentContext->context, parent); 0591 } 0592 0593 if (clang_Type_getNumTemplateArguments(type) != -1) { 0594 return createClassTemplateSpecializationType(type, decl); 0595 } 0596 0597 auto t = new StructureType; 0598 if (decl) { 0599 t->setDeclaration(decl.data()); 0600 } else { // fallback, at least give the spelling to the user 0601 t->setDeclarationId(DeclarationId(IndexedQualifiedIdentifier(QualifiedIdentifier(ClangString(clang_getTypeSpelling(type)).toString())))); 0602 } 0603 return t; 0604 } 0605 0606 template<CXTypeKind TK, EnableIf<TK == CXType_Enum> = dummy> 0607 AbstractType *createType(CXType type, CXCursor) 0608 { 0609 auto t = new EnumerationType; 0610 setIdTypeDecl(clang_getTypeDeclaration(type), t); 0611 return t; 0612 } 0613 0614 template<CXTypeKind TK, EnableIf<TK == CXType_Typedef> = dummy> 0615 AbstractType *createType(CXType type, CXCursor parent) 0616 { 0617 auto t = new TypeAliasType; 0618 CXCursor location = clang_getTypeDeclaration(type); 0619 t->setType(makeAbsType(clang_getTypedefDeclUnderlyingType(location), parent)); 0620 setIdTypeDecl(location, t); 0621 return t; 0622 } 0623 0624 template<CXTypeKind TK, EnableIf<CursorKindTraits::delayedTypeName(TK) != nullptr> = dummy> 0625 AbstractType *createType(CXType, CXCursor /*parent*/) 0626 { 0627 auto t = new DelayedType; 0628 static const IndexedTypeIdentifier id(CursorKindTraits::delayedTypeName(TK)); 0629 t->setIdentifier(id); 0630 return t; 0631 } 0632 0633 template <CXTypeKind TK, EnableIf<TK == CXType_Vector || TK == CXType_ExtVector || TK == CXType_Complex> = dummy> 0634 AbstractType* createType(CXType type, CXCursor /*parent*/) 0635 { 0636 return createDelayedType(type); 0637 } 0638 0639 template<CXTypeKind TK, EnableIf<TK == CXType_Unexposed> = dummy> 0640 AbstractType *createType(CXType type, CXCursor parent) 0641 { 0642 auto numTA = clang_Type_getNumTemplateArguments(type); 0643 // TODO: We should really expose more types to libclang! 0644 if (numTA != -1 && ClangString(clang_getTypeSpelling(type)).toString().contains(QLatin1Char('<'))) { 0645 return createClassTemplateSpecializationType(type); 0646 } 0647 0648 // Maybe it's the ElaboratedType. E.g.: "struct Type foo();" or "NS::Type foo();" or "void foo(enum Enum e);" e.t.c. 0649 auto oldType = type; 0650 0651 type = clang_getCanonicalType(type); 0652 bool isElaboratedType = type.kind != CXType_FunctionProto && type.kind != CXType_FunctionNoProto && type.kind != CXType_Unexposed && type.kind != CXType_Invalid && type.kind != CXType_Record; 0653 0654 return !isElaboratedType ? createDelayedType(oldType) : makeType(type, parent); 0655 } 0656 0657 template<CXCursorKind CK, EnableIf<CursorKindTraits::isIdentifiedType(CK) && !CursorKindTraits::isAliasType(CK) && CK != CXCursor_EnumConstantDecl> = dummy> 0658 typename IdType<CK>::Type *createType(CXCursor) 0659 { 0660 return new typename IdType<CK>::Type; 0661 } 0662 0663 template<CXCursorKind CK, EnableIf<CK == CXCursor_EnumConstantDecl> = dummy> 0664 EnumeratorType *createType(CXCursor cursor) 0665 { 0666 auto type = new EnumeratorType; 0667 type->setValue<quint64>(clang_getEnumConstantDeclUnsignedValue(cursor)); 0668 return type; 0669 } 0670 0671 template<CXCursorKind CK, EnableIf<CursorKindTraits::isAliasType(CK)> = dummy> 0672 TypeAliasType *createType(CXCursor cursor) 0673 { 0674 auto type = new TypeAliasType; 0675 type->setType(makeAbsType(clang_getTypedefDeclUnderlyingType(cursor), cursor)); 0676 return type; 0677 } 0678 0679 template <CXCursorKind CK, EnableIf<CK == CXCursor_FunctionDecl> = dummy> 0680 AbstractType* createType(CXCursor cursor) 0681 { 0682 auto clangType = clang_getCursorType(cursor); 0683 0684 #if CINDEX_VERSION_MINOR < 31 0685 if (clangType.kind == CXType_Unexposed) { 0686 // Clang sometimes can return CXType_Unexposed for CXType_FunctionProto kind. E.g. if it's AttributedType. 0687 return dispatchType<CXType_FunctionProto>(clangType, cursor); 0688 } 0689 #endif 0690 0691 return makeType(clangType, cursor); 0692 } 0693 0694 template<CXCursorKind CK, EnableIf<CK == CXCursor_LabelStmt> = dummy> 0695 AbstractType *createType(CXCursor) 0696 { 0697 auto t = new DelayedType; 0698 static const IndexedTypeIdentifier id(QStringLiteral("Label")); 0699 t->setIdentifier(id); 0700 return t; 0701 } 0702 0703 template<CXCursorKind CK, EnableIf<!CursorKindTraits::isIdentifiedType(CK) && CK != CXCursor_FunctionDecl && CK != CXCursor_LabelStmt> = dummy> 0704 AbstractType *createType(CXCursor cursor) 0705 { 0706 auto clangType = clang_getCursorType(cursor); 0707 return makeType(clangType, cursor); 0708 } 0709 0710 #if CINDEX_VERSION_MINOR >= 32 0711 template<CXTypeKind TK, EnableIf<TK == CXType_Auto> = dummy> 0712 AbstractType *createType(CXType type, CXCursor parent) 0713 { 0714 auto deducedType = clang_getCanonicalType(type); 0715 bool isDeduced = deducedType.kind != CXType_Invalid && deducedType.kind != CXType_Auto; 0716 0717 return !isDeduced ? createDelayedType(type) : makeType(deducedType, parent); 0718 } 0719 #endif 0720 0721 #if CINDEX_VERSION_MINOR >= 34 0722 template<CXTypeKind TK, EnableIf<TK == CXType_Elaborated> = dummy> 0723 AbstractType *createType(CXType type, CXCursor parent) 0724 { 0725 auto underyingType = clang_Type_getNamedType(type); 0726 return makeType(underyingType, parent); 0727 } 0728 #endif 0729 0730 /// @param declaration an optional declaration that will be associated with created type 0731 AbstractType* createClassTemplateSpecializationType(CXType type, const DeclarationPointer& declaration = {}) 0732 { 0733 auto numTA = clang_Type_getNumTemplateArguments(type); 0734 Q_ASSERT(numTA != -1); 0735 0736 auto typeDecl = clang_getTypeDeclaration(type); 0737 0738 if (!declaration && typeDecl.kind == CXCursor_NoDeclFound) { 0739 // clang_getTypeDeclaration doesn't handle all types, fall back to delayed type... 0740 return createDelayedType(type); 0741 } 0742 0743 const QString tStr = ClangString(clang_getTypeSpelling(type)).toString(); 0744 QVarLengthArray<QStringView, 8> typesStr; 0745 ParamIterator iter(u"<>", tStr); 0746 0747 while (iter) { 0748 typesStr.push_back(*iter); 0749 ++iter; 0750 } 0751 0752 auto cst = new ClassSpecializationType; 0753 0754 for (int i = 0; i < numTA; i++) { 0755 auto argumentType = clang_Type_getTemplateArgumentAsType(type, i); 0756 AbstractType::Ptr currentType; 0757 if (argumentType.kind == CXType_Invalid) { 0758 if(i >= typesStr.size()){ 0759 currentType = createDelayedType(argumentType); 0760 } else { 0761 auto t = new DelayedType; 0762 t->setIdentifier(IndexedTypeIdentifier(typesStr[i])); 0763 currentType = t; 0764 } 0765 } else { 0766 currentType = makeType(argumentType, typeDecl); 0767 } 0768 0769 if (currentType) { 0770 cst->addParameter(currentType->indexed()); 0771 } 0772 } 0773 0774 auto decl = declaration ? declaration : findDeclaration(typeDecl); 0775 0776 DUChainReadLocker lock; 0777 if (decl) { 0778 cst->setDeclaration(decl.data()); 0779 } else { // fallback, at least give the spelling to the user 0780 Identifier id(tStr); 0781 id.clearTemplateIdentifiers(); 0782 cst->setDeclarationId(DeclarationId(IndexedQualifiedIdentifier(QualifiedIdentifier(id)))); 0783 } 0784 0785 return cst; 0786 } 0787 0788 //END create* 0789 0790 //BEGIN setDeclData 0791 template<CXCursorKind CK> 0792 void setDeclData(CXCursor cursor, Declaration *decl, bool setComment = true) const; 0793 0794 template<CXCursorKind CK> 0795 void setDeclData(CXCursor cursor, MacroDefinition* decl) const; 0796 0797 template<CXCursorKind CK> 0798 void setDeclData(CXCursor cursor, ClassMemberDeclaration *decl) const; 0799 0800 template<CXCursorKind CK, EnableIf<CursorKindTraits::isClassTemplate(CK)> = dummy> 0801 void setDeclData(CXCursor cursor, ClassDeclaration* decl) const; 0802 0803 template<CXCursorKind CK, EnableIf<!CursorKindTraits::isClassTemplate(CK)> = dummy> 0804 void setDeclData(CXCursor cursor, ClassDeclaration* decl) const; 0805 0806 template<CXCursorKind CK> 0807 void setDeclData(CXCursor cursor, AbstractFunctionDeclaration* decl) const; 0808 0809 template<CXCursorKind CK> 0810 void setDeclData(CXCursor cursor, ClassFunctionDeclaration* decl) const; 0811 0812 template<CXCursorKind CK> 0813 void setDeclData(CXCursor cursor, FunctionDeclaration *decl, bool setComment = true) const; 0814 0815 template<CXCursorKind CK> 0816 void setDeclData(CXCursor cursor, FunctionDefinition *decl) const; 0817 0818 template<CXCursorKind CK> 0819 void setDeclData(CXCursor cursor, NamespaceAliasDeclaration *decl) const; 0820 0821 //END setDeclData 0822 0823 //BEGIN setDeclInCtxtData 0824 template<CXCursorKind CK> 0825 void setDeclInCtxtData(CXCursor, Declaration*) 0826 { 0827 //No-op 0828 } 0829 0830 template<CXCursorKind CK> 0831 void setDeclInCtxtData(CXCursor cursor, ClassFunctionDeclaration *decl) 0832 { 0833 // HACK to retrieve function-constness 0834 // This looks like a bug in Clang -- In theory setTypeModifiers should take care of setting the const modifier 0835 // however, clang_isConstQualifiedType() for TK == CXType_FunctionProto always returns false 0836 // TODO: Debug further 0837 auto type = decl->abstractType(); 0838 if (type) { 0839 if (clang_CXXMethod_isConst(cursor)) { 0840 type->setModifiers(type->modifiers() | AbstractType::ConstModifier); 0841 decl->setAbstractType(type); 0842 } 0843 } 0844 } 0845 0846 template<CXCursorKind CK> 0847 void setDeclInCtxtData(CXCursor cursor, FunctionDefinition *def) 0848 { 0849 setDeclInCtxtData<CK>(cursor, static_cast<FunctionDeclaration*>(def)); 0850 0851 const CXCursor canon = clang_getCanonicalCursor(cursor); 0852 if (auto decl = findDeclaration(canon)) { 0853 def->setDeclaration(decl.data()); 0854 } 0855 } 0856 //END setDeclInCtxtData 0857 0858 //BEGIN setDeclType 0859 template<CXCursorKind CK> 0860 void setDeclType(Declaration *decl, typename IdType<CK>::Type *type) 0861 { 0862 setDeclType<CK>(decl, static_cast<IdentifiedType*>(type)); 0863 setDeclType<CK>(decl, static_cast<AbstractType*>(type)); 0864 } 0865 0866 template<CXCursorKind CK> 0867 void setDeclType(Declaration *decl, IdentifiedType *type) 0868 { 0869 type->setDeclaration(decl); 0870 } 0871 0872 template<CXCursorKind CK> 0873 void setDeclType(Declaration *decl, AbstractType *type) 0874 { 0875 decl->setAbstractType(AbstractType::Ptr(type)); 0876 } 0877 //END setDeclType 0878 0879 template<CXTypeKind TK> 0880 void setTypeModifiers(CXType type, AbstractType* kdevType) const; 0881 void setTypeSize(CXType type, AbstractType* kdevType) const; 0882 0883 const CXFile m_file; 0884 const IncludeFileContexts &m_includes; 0885 0886 DeclarationPointer findDeclaration(CXCursor cursor) const; 0887 void setIdTypeDecl(CXCursor typeCursor, IdentifiedType* idType) const; 0888 0889 std::unordered_map<DUContext*, std::vector<CXCursor>> m_uses; 0890 /// At these location offsets (cf. @ref clang_getExpansionLocation) we encountered macro expansions 0891 QSet<unsigned int> m_macroExpansionLocations; 0892 mutable QHash<CXCursor, DeclarationPointer> m_cursorToDeclarationCache; 0893 CurrentContext *m_parentContext; 0894 0895 const bool m_update; 0896 }; 0897 0898 //BEGIN setTypeModifiers 0899 template<CXTypeKind TK> 0900 void Visitor::setTypeModifiers(CXType type, AbstractType* kdevType) const 0901 { 0902 quint64 modifiers = 0; 0903 if (clang_isConstQualifiedType(type)) { 0904 modifiers |= AbstractType::ConstModifier; 0905 } 0906 if (clang_isVolatileQualifiedType(type)) { 0907 modifiers |= AbstractType::VolatileModifier; 0908 } 0909 #if CINDEX_VERSION_MINOR >= 60 0910 if (TK == CXType_Atomic) { 0911 modifiers |= AbstractType::AtomicModifier; 0912 } 0913 #endif 0914 if (TK == CXType_Short || TK == CXType_UShort) { 0915 modifiers |= AbstractType::ShortModifier; 0916 } 0917 if (TK == CXType_Long || TK == CXType_LongDouble || TK == CXType_ULong) { 0918 modifiers |= AbstractType::LongModifier; 0919 } 0920 if (TK == CXType_LongLong || TK == CXType_ULongLong) { 0921 modifiers |= AbstractType::LongLongModifier; 0922 } 0923 if (TK == CXType_SChar) { 0924 modifiers |= AbstractType::SignedModifier; 0925 } 0926 if (TK == CXType_UChar || TK == CXType_UInt || TK == CXType_UShort 0927 || TK == CXType_UInt128 || TK == CXType_ULong || TK == CXType_ULongLong) 0928 { 0929 modifiers |= AbstractType::UnsignedModifier; 0930 } 0931 kdevType->setModifiers(modifiers); 0932 } 0933 //END setTypeModifiers 0934 0935 void Visitor::setTypeSize(CXType type, AbstractType* kdevType) const 0936 { 0937 if (CINDEX_VERSION_MINOR < 59) { 0938 // clang_Type_getSizeOf is unstable, see https://bugs.kde.org/show_bug.cgi?id=431391 0939 return; 0940 } 0941 0942 0943 if (kdevType->whichType() == AbstractType::TypeFunction) 0944 return; 0945 0946 type = clang_getCanonicalType(type); 0947 if (type.kind == CXType_Elaborated) 0948 return; 0949 0950 auto sizeOf = clang_Type_getSizeOf(type); 0951 if (sizeOf >= 0) { 0952 kdevType->setSizeOf(sizeOf); 0953 0954 // clang_Type_getAlignOf sometimes crashes, so better guard 0955 // it and only call it when we got a size 0956 auto alignOf = clang_Type_getAlignOf(type); 0957 if (alignOf >= 0) 0958 kdevType->setAlignOf(alignOf); 0959 } 0960 } 0961 0962 //BEGIN dispatchCursor 0963 0964 template<CXCursorKind CK, Decision IsInClass, 0965 EnableIf<IsInClass == Decision::Maybe>> 0966 CXChildVisitResult Visitor::dispatchCursor(CXCursor cursor, CXCursor parent) 0967 { 0968 const bool decision = CursorKindTraits::isClass(clang_getCursorKind(parent)); 0969 return decision ? 0970 dispatchCursor<CK, Decision::True, CursorKindTraits::isDefinition(CK)>(cursor, parent) : 0971 dispatchCursor<CK, Decision::False, CursorKindTraits::isDefinition(CK)>(cursor, parent); 0972 } 0973 0974 template<CXCursorKind CK, Decision IsInClass, Decision IsDefinition, 0975 EnableIf<IsDefinition == Decision::Maybe && IsInClass != Decision::Maybe>> 0976 CXChildVisitResult Visitor::dispatchCursor(CXCursor cursor, CXCursor parent) 0977 { 0978 IF_DEBUG(clangDebug() << "IsInClass:" << IsInClass << "- isDefinition:" << IsDefinition;) 0979 0980 const bool isDefinition = clang_isCursorDefinition(cursor); 0981 return isDefinition ? 0982 dispatchCursor<CK, IsInClass, Decision::True>(cursor, parent) : 0983 dispatchCursor<CK, IsInClass, Decision::False>(cursor, parent); 0984 } 0985 0986 template<CXCursorKind CK, Decision IsInClass, Decision IsDefinition, 0987 EnableIf<IsInClass != Decision::Maybe && IsDefinition != Decision::Maybe>> 0988 CXChildVisitResult Visitor::dispatchCursor(CXCursor cursor, CXCursor parent) 0989 { 0990 IF_DEBUG(clangDebug() << "IsInClass:" << IsInClass << "- isDefinition:" << IsDefinition;) 0991 0992 // We may end up visiting the same cursor twice in some cases 0993 // see discussion on https://git.reviewboard.kde.org/r/119526/ 0994 // TODO: Investigate why this is happening in libclang 0995 if ((CursorKindTraits::isClass(CK) || CK == CXCursor_EnumDecl) && 0996 clang_getCursorKind(parent) == CXCursor_VarDecl) { 0997 return CXChildVisit_Continue; 0998 } 0999 1000 constexpr bool isClassMember = IsInClass == Decision::True; 1001 constexpr bool isDefinition = IsDefinition == Decision::True; 1002 // always build a context for class templates and functions, otherwise we "leak" 1003 // the function/template parameter declarations into the surrounding context, 1004 // which can lead to interesting bugs, like https://bugs.kde.org/show_bug.cgi?id=368067 1005 constexpr bool hasContext = isDefinition || CursorKindTraits::isFunction(CK) || CursorKindTraits::isClassTemplate(CK); 1006 1007 return buildDeclaration<CK, typename DeclType<CK, isDefinition, isClassMember>::Type, hasContext>(cursor); 1008 } 1009 1010 //END dispatchCursor 1011 1012 //BEGIN setDeclData 1013 template<CXCursorKind CK> 1014 void Visitor::setDeclData(CXCursor cursor, Declaration *decl, bool setComment) const 1015 { 1016 if (setComment) 1017 #if CINDEX_VERSION_MINOR < 100 // FIXME https://bugs.llvm.org/show_bug.cgi?id=35333 1018 decl->setComment(KDevelop::formatComment(ClangString(clang_Cursor_getRawCommentText(cursor)).toByteArray())); 1019 #else 1020 decl->setComment(makeComment(clang_Cursor_getParsedComment(cursor))); 1021 #endif 1022 if (CursorKindTraits::isAliasType(CK)) { 1023 decl->setIsTypeAlias(true); 1024 } 1025 if (CK == CXCursor_Namespace) 1026 decl->setKind(Declaration::Namespace); 1027 if (CK == CXCursor_EnumDecl || CK == CXCursor_EnumConstantDecl || CursorKindTraits::isClass(CK) || CursorKindTraits::isAliasType(CK)) 1028 decl->setKind(Declaration::Type); 1029 1030 int isAlwaysDeprecated; 1031 clang_getCursorPlatformAvailability(cursor, &isAlwaysDeprecated, nullptr, nullptr, nullptr, nullptr, 0); 1032 decl->setDeprecated(isAlwaysDeprecated); 1033 } 1034 1035 /// @return the position in @p contents where the macro identifier ends. 1036 static int skipMacroIdentifier(QStringView contents) 1037 { 1038 const auto isPartOfIdentifier = [](QChar c) { 1039 return c.isLetterOrNumber() || c == QLatin1Char('_'); 1040 }; 1041 1042 int posAfterMacroId = 0; 1043 while (posAfterMacroId < contents.size()) { 1044 posAfterMacroId = std::find_if_not(contents.cbegin() + posAfterMacroId, contents.cend(), isPartOfIdentifier) 1045 - contents.cbegin(); 1046 1047 // Escaped newline characters can separate parts of a macro identifier or a macro identifier and '(' in a 1048 // function-like macro. And the escape character can be separated from the '\n' it escapes by any number of 1049 // whitespace characters other than '\n'. Furthermore, the same escaped-newline pattern can precede the macro 1050 // identifier. Simply skip such escape and whitespace characters as displaying them in a tooltip is not useful. 1051 if (posAfterMacroId == contents.size() || contents[posAfterMacroId] != QLatin1Char{'\\'}) { 1052 break; // no escape character => the macro identifier ends here 1053 } 1054 ++posAfterMacroId; 1055 1056 bool foundNewLineCharacter = false; 1057 while (posAfterMacroId < contents.size() && contents[posAfterMacroId].isSpace()) { 1058 if (contents[posAfterMacroId++] == QLatin1Char{'\n'}) { 1059 foundNewLineCharacter = true; 1060 break; 1061 } 1062 } 1063 if (!foundNewLineCharacter) { 1064 // The escape character does not escape a newline character. The code probably does not compile. Go back to 1065 // the previous character to prevent the calling code from wrongly considering this macro function-like. 1066 --posAfterMacroId; 1067 break; 1068 } 1069 } 1070 1071 return posAfterMacroId; 1072 } 1073 1074 template<CXCursorKind CK> 1075 void Visitor::setDeclData(CXCursor cursor, MacroDefinition* decl) const 1076 { 1077 setDeclData<CK>(cursor, static_cast<Declaration*>(decl)); 1078 1079 if (m_update) { 1080 decl->clearParameters(); 1081 } 1082 1083 auto unit = clang_Cursor_getTranslationUnit(cursor); 1084 auto range = clang_getCursorExtent(cursor); 1085 1086 // TODO: Quite lacking API in libclang here. 1087 // No way to find out if this macro is function-like or not 1088 // cf. https://clang.llvm.org/doxygen/classclang_1_1MacroInfo.html 1089 // And no way to get the actual definition text range 1090 // Should be quite easy to expose that in libclang, though 1091 // Let' still get some basic support for this and parse on our own, it's not that difficult 1092 1093 // Macro definition strings get '\n' replaced with "<br/>", then are rendered as HTML, which ignores whitespace. 1094 // Newline characters are escaped in macro definiton C++ code. ClangUtils::getRawContents() preserves the escape 1095 // characters: its return value contains "\\\n". ClangUtils::getRawContents() removes whitespace, including the 1096 // escaped newline characters, at the end of the definition string. 1097 // Trim definition string views before passing them to MacroDefinition::setDefinition() to facilitate testing. 1098 // This trimming never strips newline characters in practice (shouldn't have been a problem even if it did). 1099 const auto setDefinition = [decl](QStringView definition) { 1100 decl->setDefinition(IndexedString{definition.trimmed()}); 1101 }; 1102 1103 const QString rawContentsString = ClangUtils::getRawContents(unit, range); 1104 // Use a QStringView contents, because it works as fast as or faster than a QString in the code below. 1105 const QStringView contents(rawContentsString); 1106 1107 const int posAfterMacroId = skipMacroIdentifier(contents); 1108 1109 if (posAfterMacroId == contents.size() || contents[posAfterMacroId] != QLatin1Char{'('}) { 1110 // '(', a space, a tab or '/' (a comment) usually follows a macro identifier. 1111 // Compilers consider a macro function-like only if '(' immediately follows its identifier. 1112 decl->setFunctionLike(false); 1113 setDefinition(contents.mid(posAfterMacroId)); 1114 return; 1115 } 1116 1117 decl->setFunctionLike(true); 1118 1119 // extract macro function parameters 1120 ParamIterator paramIt(u"()", contents, posAfterMacroId); 1121 while (paramIt) { 1122 decl->addParameter(IndexedString(*paramIt)); 1123 ++paramIt; 1124 } 1125 1126 const auto paramEndPosition = paramIt.position(); 1127 if (paramEndPosition > 0 && contents[paramEndPosition - 1] == QLatin1Char{')'}) { 1128 setDefinition(contents.mid(paramEndPosition)); 1129 } else { 1130 // unlikely: invalid macro definition, insert the complete #define statement 1131 const QString definition = QLatin1String("#define ") + contents; 1132 setDefinition(definition); 1133 } 1134 } 1135 1136 template<CXCursorKind CK> 1137 void Visitor::setDeclData(CXCursor cursor, ClassMemberDeclaration *decl) const 1138 { 1139 setDeclData<CK>(cursor, static_cast<Declaration*>(decl)); 1140 //A CXCursor_VarDecl in a class is static (otherwise it'd be a CXCursor_FieldDecl) 1141 if (CK == CXCursor_VarDecl) 1142 decl->setStatic(true); 1143 decl->setAccessPolicy(CursorKindTraits::kdevAccessPolicy(clang_getCXXAccessSpecifier(cursor))); 1144 1145 #if CINDEX_VERSION_MINOR >= 32 1146 decl->setMutable(clang_CXXField_isMutable(cursor)); 1147 #endif 1148 1149 #if CINDEX_VERSION_MINOR >= 30 1150 auto offset = clang_Cursor_getOffsetOfField(cursor); 1151 if (offset >= 0) { 1152 decl->setBitOffsetOf(offset); 1153 } 1154 #endif 1155 1156 #if CINDEX_VERSION_MINOR >= 16 1157 if (clang_Cursor_isBitField(cursor)) { 1158 const auto bitWidth = clang_getFieldDeclBitWidth(cursor); 1159 decl->setBitWidth(bitWidth == -1 ? ClassMemberDeclaration::ValueDependentBitWidth : bitWidth); 1160 } else { 1161 decl->setBitWidth(ClassMemberDeclaration::NotABitField); 1162 } 1163 #endif 1164 1165 if (clang_isCursorDefinition(cursor)) { 1166 decl->setDeclarationIsDefinition(true); 1167 } 1168 } 1169 1170 template<CXCursorKind CK, EnableIf<CursorKindTraits::isClassTemplate(CK)>> 1171 void Visitor::setDeclData(CXCursor cursor, ClassDeclaration* decl) const 1172 { 1173 CXCursorKind kind = clang_getTemplateCursorKind(cursor); 1174 switch (kind) { 1175 case CXCursor_UnionDecl: setDeclData<CXCursor_UnionDecl>(cursor, decl); break; 1176 case CXCursor_StructDecl: setDeclData<CXCursor_StructDecl>(cursor, decl); break; 1177 case CXCursor_ClassDecl: setDeclData<CXCursor_ClassDecl>(cursor, decl); break; 1178 default: Q_ASSERT(false); break; 1179 } 1180 } 1181 1182 template<CXCursorKind CK, EnableIf<!CursorKindTraits::isClassTemplate(CK)>> 1183 void Visitor::setDeclData(CXCursor cursor, ClassDeclaration* decl) const 1184 { 1185 if (m_update) { 1186 decl->clearBaseClasses(); 1187 } 1188 setDeclData<CK>(cursor, static_cast<ClassMemberDeclaration*>(decl)); 1189 if (CK == CXCursor_UnionDecl) 1190 decl->setClassType(ClassDeclarationData::Union); 1191 if (CK == CXCursor_StructDecl) 1192 decl->setClassType(ClassDeclarationData::Struct); 1193 if (clang_isCursorDefinition(cursor)) { 1194 decl->setDeclarationIsDefinition(true); 1195 } 1196 } 1197 1198 template<CXCursorKind CK> 1199 void Visitor::setDeclData(CXCursor cursor, AbstractFunctionDeclaration* decl) const 1200 { 1201 if (m_update) { 1202 decl->clearDefaultParameters(); 1203 } 1204 // No setDeclData<CK>(...) here: AbstractFunctionDeclaration is an interface 1205 // TODO: Can we get the default arguments directly from Clang? 1206 // also see http://clang-developers.42468.n3.nabble.com/Finding-default-value-for-function-argument-with-clang-c-API-td4036919.html 1207 const QVector<QString> defaultArgs = ClangUtils::getDefaultArguments(cursor, ClangUtils::MinimumSize); 1208 for (const QString& defaultArg : defaultArgs) { 1209 decl->addDefaultParameter(IndexedString(defaultArg)); 1210 } 1211 } 1212 1213 template<CXCursorKind CK> 1214 void Visitor::setDeclData(CXCursor cursor, ClassFunctionDeclaration* decl) const 1215 { 1216 setDeclData<CK>(cursor, static_cast<AbstractFunctionDeclaration*>(decl)); 1217 setDeclData<CK>(cursor, static_cast<ClassMemberDeclaration*>(decl)); 1218 decl->setIsAbstract(clang_CXXMethod_isPureVirtual(cursor)); 1219 decl->setStatic(clang_CXXMethod_isStatic(cursor)); 1220 decl->setVirtual(clang_CXXMethod_isVirtual(cursor)); 1221 1222 // TODO: Set flags in one go? (needs new API in kdevplatform) 1223 const auto attributes = ClangUtils::specialAttributes(cursor); 1224 decl->setIsSignal(attributes & FunctionSignalFlag); 1225 decl->setIsSlot(attributes & FunctionSlotFlag); 1226 decl->setIsFinal(attributes & FinalFunctionFlag); 1227 } 1228 1229 template<CXCursorKind CK> 1230 void Visitor::setDeclData(CXCursor cursor, FunctionDeclaration *decl, bool setComment) const 1231 { 1232 setDeclData<CK>(cursor, static_cast<AbstractFunctionDeclaration*>(decl)); 1233 setDeclData<CK>(cursor, static_cast<Declaration*>(decl), setComment); 1234 } 1235 1236 template<CXCursorKind CK> 1237 void Visitor::setDeclData(CXCursor cursor, FunctionDefinition *decl) const 1238 { 1239 bool setComment = clang_equalCursors(clang_getCanonicalCursor(cursor), cursor); 1240 setDeclData<CK>(cursor, static_cast<FunctionDeclaration*>(decl), setComment); 1241 } 1242 1243 template<CXCursorKind CK> 1244 void Visitor::setDeclData(CXCursor cursor, NamespaceAliasDeclaration *decl) const 1245 { 1246 setDeclData<CK>(cursor, static_cast<Declaration*>(decl)); 1247 clang_visitChildren(cursor, [] (CXCursor cursor, CXCursor parent, CXClientData data) -> CXChildVisitResult { 1248 if (clang_getCursorKind(cursor) == CXCursor_NamespaceRef) { 1249 const auto id = QualifiedIdentifier(ClangString(clang_getCursorSpelling(cursor)).toString()); 1250 reinterpret_cast<NamespaceAliasDeclaration*>(data)->setImportIdentifier(id); 1251 return CXChildVisit_Break; 1252 } else { 1253 return visitCursor(cursor, parent, data); 1254 } 1255 }, decl); 1256 } 1257 //END setDeclData 1258 1259 //BEGIN build* 1260 template<CXCursorKind CK, class DeclType, bool hasContext> 1261 CXChildVisitResult Visitor::buildDeclaration(CXCursor cursor) 1262 { 1263 auto id = makeId(cursor); 1264 if (CK == CXCursor_UnexposedDecl && id.isEmpty()) { 1265 // skip unexposed declarations that have no identifier set 1266 // this is useful to skip e.g. friend declarations 1267 return CXChildVisit_Recurse; 1268 } 1269 IF_DEBUG(clangDebug() << "id:" << id << "- CK:" << CK << "- DeclType:" << typeid(DeclType).name() << "- hasContext:" << hasContext;) 1270 1271 // Code path for class declarations that may be defined "out-of-line", e.g. 1272 // "SomeNameSpace::SomeClass {};" 1273 QScopedPointer<CurrentContext> helperContext; 1274 if (CursorKindTraits::isClass(CK) || CursorKindTraits::isFunction(CK)) { 1275 const auto lexicalParent = clang_getCursorLexicalParent(cursor); 1276 const auto semanticParent = clang_getCursorSemanticParent(cursor); 1277 const bool isOutOfLine = !clang_equalCursors(lexicalParent, semanticParent); 1278 if (isOutOfLine) { 1279 const QString scope = ClangUtils::getScope(cursor); 1280 auto context = createContext<CK, DUContext::Helper>(cursor, QualifiedIdentifier(scope)); 1281 helperContext.reset(new CurrentContext(context, m_parentContext->keepAliveContexts)); 1282 } 1283 } 1284 1285 // if helperContext is null, this is a no-op 1286 PushValue<CurrentContext*> pushCurrent(m_parentContext, helperContext.isNull() ? m_parentContext : helperContext.data()); 1287 1288 if (hasContext) { 1289 auto context = createContext<CK, CursorKindTraits::contextType(CK)>(cursor, QualifiedIdentifier(id)); 1290 createDeclaration<CK, DeclType>(cursor, id, context); 1291 CurrentContext newParent(context, m_parentContext->keepAliveContexts); 1292 PushValue<CurrentContext*> pushCurrent(m_parentContext, &newParent); 1293 clang_visitChildren(cursor, &visitCursor, this); 1294 return CXChildVisit_Continue; 1295 } 1296 createDeclaration<CK, DeclType>(cursor, id, nullptr); 1297 return CXChildVisit_Recurse; 1298 } 1299 1300 CXChildVisitResult Visitor::buildParmDecl(CXCursor cursor) 1301 { 1302 return buildDeclaration<CXCursor_ParmDecl, typename DeclType<CXCursor_ParmDecl, false, false>::Type, false>(cursor); 1303 } 1304 1305 CXChildVisitResult Visitor::buildUse(CXCursor cursor) 1306 { 1307 m_uses[m_parentContext->context].push_back(cursor); 1308 return cursor.kind == CXCursor_DeclRefExpr || cursor.kind == CXCursor_MemberRefExpr ? 1309 CXChildVisit_Recurse : CXChildVisit_Continue; 1310 } 1311 1312 CXChildVisitResult Visitor::buildMacroExpansion(CXCursor cursor) 1313 { 1314 buildUse(cursor); 1315 1316 // cache that we encountered a macro expansion at this location 1317 unsigned int offset; 1318 clang_getSpellingLocation(clang_getCursorLocation(cursor), nullptr, nullptr, nullptr, &offset); 1319 m_macroExpansionLocations << offset; 1320 1321 return CXChildVisit_Recurse; 1322 } 1323 1324 template<CXCursorKind CK> 1325 CXChildVisitResult Visitor::buildCompoundStatement(CXCursor cursor) 1326 { 1327 if (CK == CXCursor_LambdaExpr || m_parentContext->context->type() == DUContext::Function) 1328 { 1329 auto context = createContext<CK, CK == CXCursor_LambdaExpr ? DUContext::Function : DUContext::Other>(cursor); 1330 CurrentContext newParent(context, m_parentContext->keepAliveContexts); 1331 PushValue<CurrentContext*> pushCurrent(m_parentContext, &newParent); 1332 clang_visitChildren(cursor, &visitCursor, this); 1333 return CXChildVisit_Continue; 1334 } 1335 return CXChildVisit_Recurse; 1336 } 1337 1338 CXChildVisitResult Visitor::buildCXXBaseSpecifier(CXCursor cursor) 1339 { 1340 auto currentContext = m_parentContext->context; 1341 1342 bool virtualInherited = clang_isVirtualBase(cursor); 1343 Declaration::AccessPolicy access = CursorKindTraits::kdevAccessPolicy(clang_getCXXAccessSpecifier(cursor)); 1344 1345 auto classDeclCursor = clang_getCursorReferenced(cursor); 1346 auto decl = findDeclaration(classDeclCursor); 1347 if (!decl) { 1348 // this happens for templates with template-dependent base classes e.g. - dunno whether we can/should do more here 1349 clangDebug() << "failed to find declaration for base specifier:" << clang_getCursorDisplayName(cursor); 1350 return CXChildVisit_Recurse; 1351 } 1352 1353 DUChainWriteLocker lock; 1354 contextImportDecl(currentContext, decl); 1355 auto classDecl = dynamic_cast<ClassDeclaration*>(currentContext->owner()); 1356 Q_ASSERT(classDecl); 1357 1358 classDecl->addBaseClass({decl->indexedType(), access, virtualInherited}); 1359 return CXChildVisit_Recurse; 1360 } 1361 1362 template<bool IsInClass> 1363 CXChildVisitResult Visitor::buildTypeAliasTemplateDecl(CXCursor cursor) 1364 { 1365 auto aliasDecl = findEmbeddedTypeAlias(cursor); 1366 // NOTE: using aliasDecl here averts having to add a workaround to makeId() 1367 auto id = makeId(aliasDecl); 1368 // create template context to prevent leaking child template params 1369 auto context = createContext<CXCursor_TypeAliasTemplateDecl, DUContext::Template>(cursor, QualifiedIdentifier(id)); 1370 using DeclType = typename DeclType<CXCursor_TypeAliasDecl, false, IsInClass>::Type; 1371 createDeclaration<CXCursor_TypeAliasDecl, DeclType>(aliasDecl, id, context); 1372 CurrentContext newParent(context, m_parentContext->keepAliveContexts); 1373 PushValue<CurrentContext*> pushCurrent(m_parentContext, &newParent); 1374 clang_visitChildren(cursor, [] (CXCursor cursor, CXCursor parent, CXClientData data) { 1375 // NOTE: immediately recurse into embedded alias decl 1376 return clang_getCursorKind(cursor) == CXCursor_TypeAliasDecl ? 1377 CXChildVisit_Recurse : visitCursor(cursor, parent, data); 1378 }, this); 1379 return CXChildVisit_Continue; 1380 } 1381 //END build* 1382 1383 DeclarationPointer Visitor::findDeclaration(CXCursor cursor) const 1384 { 1385 const auto it = m_cursorToDeclarationCache.constFind(cursor); 1386 if (it != m_cursorToDeclarationCache.constEnd()) { 1387 return *it; 1388 } 1389 1390 // fallback, and cache result 1391 auto decl = ClangHelpers::findDeclaration(cursor, m_includes); 1392 1393 m_cursorToDeclarationCache.insert(cursor, decl); 1394 return decl; 1395 } 1396 1397 void Visitor::setIdTypeDecl(CXCursor typeCursor, IdentifiedType* idType) const 1398 { 1399 DeclarationPointer decl = findDeclaration(typeCursor); 1400 DUChainReadLocker lock; 1401 if (decl) { 1402 idType->setDeclaration(decl.data()); 1403 } 1404 } 1405 1406 AbstractType *Visitor::makeType(CXType type, CXCursor parent) 1407 { 1408 #define UseKind(TypeKind) case TypeKind: return dispatchType<TypeKind>(type, parent) 1409 switch (type.kind) { 1410 UseKind(CXType_Void); 1411 UseKind(CXType_Bool); 1412 UseKind(CXType_Short); 1413 UseKind(CXType_UShort); 1414 UseKind(CXType_Int); 1415 UseKind(CXType_UInt); 1416 UseKind(CXType_Long); 1417 UseKind(CXType_ULong); 1418 UseKind(CXType_LongLong); 1419 UseKind(CXType_ULongLong); 1420 UseKind(CXType_Half); 1421 UseKind(CXType_Float); 1422 UseKind(CXType_LongDouble); 1423 UseKind(CXType_Double); 1424 UseKind(CXType_Char_U); 1425 UseKind(CXType_Char_S); 1426 UseKind(CXType_UChar); 1427 UseKind(CXType_SChar); 1428 UseKind(CXType_Char16); 1429 UseKind(CXType_Char32); 1430 UseKind(CXType_Pointer); 1431 UseKind(CXType_BlockPointer); 1432 UseKind(CXType_MemberPointer); 1433 UseKind(CXType_ObjCObjectPointer); 1434 UseKind(CXType_ConstantArray); 1435 UseKind(CXType_VariableArray); 1436 UseKind(CXType_IncompleteArray); 1437 UseKind(CXType_DependentSizedArray); 1438 UseKind(CXType_LValueReference); 1439 UseKind(CXType_RValueReference); 1440 UseKind(CXType_FunctionNoProto); 1441 UseKind(CXType_FunctionProto); 1442 UseKind(CXType_Record); 1443 UseKind(CXType_Enum); 1444 UseKind(CXType_Typedef); 1445 UseKind(CXType_Int128); 1446 UseKind(CXType_UInt128); 1447 UseKind(CXType_Vector); 1448 UseKind(CXType_ExtVector); 1449 UseKind(CXType_Unexposed); 1450 UseKind(CXType_WChar); 1451 UseKind(CXType_ObjCInterface); 1452 UseKind(CXType_ObjCId); 1453 UseKind(CXType_ObjCClass); 1454 UseKind(CXType_ObjCSel); 1455 UseKind(CXType_NullPtr); 1456 #if CINDEX_VERSION_MINOR >= 32 1457 UseKind(CXType_Auto); 1458 #endif 1459 #if CINDEX_VERSION_MINOR >= 34 1460 UseKind(CXType_Elaborated); 1461 #endif 1462 #if CINDEX_VERSION_MINOR >= 38 1463 UseKind(CXType_Float128); 1464 #endif 1465 #if CINDEX_VERSION_MINOR >= 60 1466 UseKind(CXType_Atomic); 1467 #endif 1468 UseKind(CXType_Complex); 1469 UseKind(CXType_OCLImage1dRO); 1470 UseKind(CXType_OCLImage1dArrayRO); 1471 UseKind(CXType_OCLImage1dBufferRO); 1472 UseKind(CXType_OCLImage2dRO); 1473 UseKind(CXType_OCLImage2dArrayRO); 1474 UseKind(CXType_OCLImage2dDepthRO); 1475 UseKind(CXType_OCLImage2dArrayDepthRO); 1476 UseKind(CXType_OCLImage2dMSAARO); 1477 UseKind(CXType_OCLImage2dArrayMSAARO); 1478 UseKind(CXType_OCLImage2dMSAADepthRO); 1479 UseKind(CXType_OCLImage2dArrayMSAADepthRO); 1480 UseKind(CXType_OCLImage3dRO); 1481 UseKind(CXType_OCLImage1dWO); 1482 UseKind(CXType_OCLImage1dArrayWO); 1483 UseKind(CXType_OCLImage1dBufferWO); 1484 UseKind(CXType_OCLImage2dWO); 1485 UseKind(CXType_OCLImage2dArrayWO); 1486 UseKind(CXType_OCLImage2dDepthWO); 1487 UseKind(CXType_OCLImage2dArrayDepthWO); 1488 UseKind(CXType_OCLImage2dMSAAWO); 1489 UseKind(CXType_OCLImage2dArrayMSAAWO); 1490 UseKind(CXType_OCLImage2dMSAADepthWO); 1491 UseKind(CXType_OCLImage2dArrayMSAADepthWO); 1492 UseKind(CXType_OCLImage3dWO); 1493 UseKind(CXType_OCLImage1dRW); 1494 UseKind(CXType_OCLImage1dArrayRW); 1495 UseKind(CXType_OCLImage1dBufferRW); 1496 UseKind(CXType_OCLImage2dRW); 1497 UseKind(CXType_OCLImage2dArrayRW); 1498 UseKind(CXType_OCLImage2dDepthRW); 1499 UseKind(CXType_OCLImage2dArrayDepthRW); 1500 UseKind(CXType_OCLImage2dMSAARW); 1501 UseKind(CXType_OCLImage2dArrayMSAARW); 1502 UseKind(CXType_OCLImage2dMSAADepthRW); 1503 UseKind(CXType_OCLImage2dArrayMSAADepthRW); 1504 UseKind(CXType_OCLImage3dRW); 1505 UseKind(CXType_OCLSampler); 1506 UseKind(CXType_OCLEvent); 1507 UseKind(CXType_OCLQueue); 1508 UseKind(CXType_OCLReserveID); 1509 case CXType_Invalid: 1510 return nullptr; 1511 default: 1512 qCWarning(KDEV_CLANG) << "Unhandled type:" << type.kind << clang_getTypeSpelling(type); 1513 return nullptr; 1514 } 1515 #undef UseKind 1516 } 1517 1518 RangeInRevision rangeInRevisionForUse(CXCursor cursor, CXCursorKind referencedCursorKind, CXSourceRange useRange, const QSet<unsigned int>& macroExpansionLocations) 1519 { 1520 auto range = ClangRange(useRange).toRangeInRevision(); 1521 1522 //TODO: Fix in clang, happens for operator<<, operator<, probably more 1523 if (clang_Range_isNull(useRange)) { 1524 useRange = clang_getCursorExtent(cursor); 1525 range = ClangRange(useRange).toRangeInRevision(); 1526 } 1527 1528 if (referencedCursorKind == CXCursor_ConversionFunction) { 1529 range.end = range.start; 1530 range.start.column--; 1531 } 1532 1533 // For uses inside macro expansions, create an empty use range at the spelling location 1534 // the empty range is required in order to not "overlap" the macro expansion range 1535 // and to allow proper navigation for the macro expansion 1536 // also see JSON test 'macros.cpp' 1537 if (clang_getCursorKind(cursor) != CXCursor_MacroExpansion) { 1538 unsigned int expansionLocOffset; 1539 const auto spellingLocation = clang_getRangeStart(useRange); 1540 clang_getExpansionLocation(spellingLocation, nullptr, nullptr, nullptr, &expansionLocOffset); 1541 if (macroExpansionLocations.contains(expansionLocOffset)) { 1542 unsigned int spellingLocOffset; 1543 clang_getSpellingLocation(spellingLocation, nullptr, nullptr, nullptr, &spellingLocOffset); 1544 if (spellingLocOffset == expansionLocOffset) { 1545 range.end = range.start; 1546 } 1547 } 1548 } else { 1549 // Workaround for wrong use range returned by clang for macro expansions 1550 const auto contents = ClangUtils::getRawContents(clang_Cursor_getTranslationUnit(cursor), useRange); 1551 const int firstOpeningParen = contents.indexOf(QLatin1Char('(')); 1552 if (firstOpeningParen != -1) { 1553 range.end.column = range.start.column + firstOpeningParen; 1554 range.end.line = range.start.line; 1555 } 1556 } 1557 1558 return range; 1559 } 1560 1561 Visitor::Visitor(CXTranslationUnit tu, CXFile file, 1562 const IncludeFileContexts& includes, const bool update) 1563 : m_file(file) 1564 , m_includes(includes) 1565 , m_parentContext(nullptr) 1566 , m_update(update) 1567 { 1568 CXCursor tuCursor = clang_getTranslationUnitCursor(tu); 1569 auto top = includes[file]; 1570 1571 // when updating, this contains child contexts that should be kept alive 1572 // even when they are not part of the AST anymore 1573 // this is required for some assistants, such as the signature assistant 1574 QSet<DUContext*> keepAliveContexts; 1575 { 1576 DUChainReadLocker lock; 1577 const auto problems = top->problems(); 1578 for (const auto& problem : problems) { 1579 const auto& desc = problem->description(); 1580 if (desc.startsWith(QLatin1String("Return type of out-of-line definition of '")) 1581 && desc.endsWith(QLatin1String("' differs from that in the declaration"))) { 1582 auto ctx = top->findContextAt(problem->range().start); 1583 // keep the context and its parents alive 1584 // this also keeps declarations in this context alive 1585 while (ctx) { 1586 keepAliveContexts << ctx; 1587 ctx = ctx->parentContext(); 1588 } 1589 } 1590 } 1591 } 1592 1593 CurrentContext parent(top, keepAliveContexts); 1594 m_parentContext = &parent; 1595 clang_visitChildren(tuCursor, &visitCursor, this); 1596 1597 if (m_update) { 1598 DUChainWriteLocker lock; 1599 top->deleteUsesRecursively(); 1600 } 1601 for (const auto &contextUses : m_uses) { 1602 for (const auto &cursor : contextUses.second) { 1603 auto referenced = referencedCursor(cursor); 1604 if (clang_Cursor_isNull(referenced)) { 1605 continue; 1606 } 1607 // first, try the canonical referenced cursor 1608 // this is important to get the correct function declaration e.g. 1609 auto canonicalReferenced = clang_getCanonicalCursor(referenced); 1610 auto used = findDeclaration(canonicalReferenced); 1611 1612 if (!used) { 1613 // if the above failed, try the non-canonicalized version as a fallback 1614 // this is required for friend declarations that occur before 1615 // the real declaration. there, the canonical cursor points to 1616 // the friend declaration which is not what we are looking for 1617 used = findDeclaration(referenced); 1618 } 1619 1620 if (!used) { // as a last resort, try to resolve the forward declaration 1621 DUChainReadLocker lock; 1622 DeclarationPointer decl = ClangHelpers::findForwardDeclaration(clang_getCursorType(referenced), contextUses.first, referenced); 1623 used = decl; 1624 if (!used) { 1625 continue; 1626 } 1627 } 1628 1629 #if CINDEX_VERSION_MINOR >= 29 1630 if (clang_Cursor_getNumTemplateArguments(referenced) >= 0) { 1631 // Ideally, we don't need this, but for function templates clang_getCanonicalCursor returns a function definition 1632 // See also the testUsesCreatedForDeclarations test 1633 DUChainReadLocker lock; 1634 used = DUChainUtils::declarationForDefinition(used.data()); 1635 } 1636 #endif 1637 1638 const auto useRange = clang_getCursorReferenceNameRange(cursor, 0, 0); 1639 const auto range = rangeInRevisionForUse(cursor, referenced.kind, useRange, m_macroExpansionLocations); 1640 1641 DUChainWriteLocker lock; 1642 auto usedIndex = top->indexForUsedDeclaration(used.data()); 1643 contextUses.first->createUse(usedIndex, range); 1644 } 1645 } 1646 } 1647 1648 //END Visitor 1649 1650 CXChildVisitResult visitCursor(CXCursor cursor, CXCursor parent, CXClientData data) 1651 { 1652 auto *visitor = static_cast<Visitor*>(data); 1653 1654 const auto kind = clang_getCursorKind(cursor); 1655 1656 auto location = clang_getCursorLocation(cursor); 1657 CXFile file; 1658 clang_getFileLocation(location, &file, nullptr, nullptr, nullptr); 1659 if (!ClangUtils::isFileEqual(file, visitor->m_file)) { 1660 // don't skip MemberRefExpr with invalid location, see also: 1661 // http://lists.cs.uiuc.edu/pipermail/cfe-dev/2015-May/043114.html 1662 const auto invalidMemberRefExpr = !file && kind == CXCursor_MemberRefExpr; 1663 // also don't skip unexposed declarations, which may e.g. be an `extern "C"` directive 1664 const auto unexposedDecl = file && kind == CXCursor_UnexposedDecl; 1665 if (!invalidMemberRefExpr && !unexposedDecl) { 1666 return CXChildVisit_Continue; 1667 } 1668 } 1669 1670 #define UseCursorKind(CursorKind, ...) case CursorKind: return visitor->dispatchCursor<CursorKind>(__VA_ARGS__); 1671 switch (kind) 1672 { 1673 UseCursorKind(CXCursor_UnexposedDecl, cursor, parent); 1674 UseCursorKind(CXCursor_StructDecl, cursor, parent); 1675 UseCursorKind(CXCursor_UnionDecl, cursor, parent); 1676 UseCursorKind(CXCursor_ClassDecl, cursor, parent); 1677 UseCursorKind(CXCursor_EnumDecl, cursor, parent); 1678 UseCursorKind(CXCursor_FieldDecl, cursor, parent); 1679 UseCursorKind(CXCursor_EnumConstantDecl, cursor, parent); 1680 UseCursorKind(CXCursor_FunctionDecl, cursor, parent); 1681 UseCursorKind(CXCursor_VarDecl, cursor, parent); 1682 UseCursorKind(CXCursor_TypeAliasDecl, cursor, parent); 1683 UseCursorKind(CXCursor_TypedefDecl, cursor, parent); 1684 UseCursorKind(CXCursor_CXXMethod, cursor, parent); 1685 UseCursorKind(CXCursor_Namespace, cursor, parent); 1686 UseCursorKind(CXCursor_NamespaceAlias, cursor, parent); 1687 UseCursorKind(CXCursor_Constructor, cursor, parent); 1688 UseCursorKind(CXCursor_Destructor, cursor, parent); 1689 UseCursorKind(CXCursor_ConversionFunction, cursor, parent); 1690 UseCursorKind(CXCursor_TemplateTypeParameter, cursor, parent); 1691 UseCursorKind(CXCursor_NonTypeTemplateParameter, cursor, parent); 1692 UseCursorKind(CXCursor_TemplateTemplateParameter, cursor, parent); 1693 UseCursorKind(CXCursor_FunctionTemplate, cursor, parent); 1694 UseCursorKind(CXCursor_ClassTemplate, cursor, parent); 1695 UseCursorKind(CXCursor_ClassTemplatePartialSpecialization, cursor, parent); 1696 UseCursorKind(CXCursor_ObjCInterfaceDecl, cursor, parent); 1697 UseCursorKind(CXCursor_ObjCCategoryDecl, cursor, parent); 1698 UseCursorKind(CXCursor_ObjCProtocolDecl, cursor, parent); 1699 UseCursorKind(CXCursor_ObjCPropertyDecl, cursor, parent); 1700 UseCursorKind(CXCursor_ObjCIvarDecl, cursor, parent); 1701 UseCursorKind(CXCursor_ObjCInstanceMethodDecl, cursor, parent); 1702 UseCursorKind(CXCursor_ObjCClassMethodDecl, cursor, parent); 1703 UseCursorKind(CXCursor_ObjCImplementationDecl, cursor, parent); 1704 UseCursorKind(CXCursor_ObjCCategoryImplDecl, cursor, parent); 1705 UseCursorKind(CXCursor_MacroDefinition, cursor, parent); 1706 UseCursorKind(CXCursor_LabelStmt, cursor, parent); 1707 case CXCursor_TypeRef: 1708 case CXCursor_TemplateRef: 1709 case CXCursor_NamespaceRef: 1710 case CXCursor_MemberRef: 1711 case CXCursor_LabelRef: 1712 case CXCursor_OverloadedDeclRef: 1713 case CXCursor_VariableRef: 1714 case CXCursor_DeclRefExpr: 1715 case CXCursor_MemberRefExpr: 1716 case CXCursor_ObjCClassRef: 1717 return visitor->buildUse(cursor); 1718 case CXCursor_MacroExpansion: 1719 return visitor->buildMacroExpansion(cursor); 1720 case CXCursor_CompoundStmt: 1721 return visitor->buildCompoundStatement<CXCursor_CompoundStmt>(cursor); 1722 case CXCursor_LambdaExpr: 1723 return visitor->buildCompoundStatement<CXCursor_LambdaExpr>(cursor); 1724 case CXCursor_CXXBaseSpecifier: 1725 return visitor->buildCXXBaseSpecifier(cursor); 1726 case CXCursor_ParmDecl: 1727 return visitor->buildParmDecl(cursor); 1728 // TODO: fix upstream and then just adapt this to UseCursorKind() 1729 case CXCursor_TypeAliasTemplateDecl: 1730 return visitor->dispatchTypeAliasTemplate(cursor, parent); 1731 default: 1732 return CXChildVisit_Recurse; 1733 } 1734 } 1735 1736 } 1737 1738 namespace Builder { 1739 1740 void visit(CXTranslationUnit tu, CXFile file, const IncludeFileContexts& includes, const bool update) 1741 { 1742 Visitor visitor(tu, file, includes, update); 1743 } 1744 1745 }