void ProBoundsPointerArithmeticCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; // Flag all operators +, -, +=, -=, ++, -- that result in a pointer Finder->addMatcher( binaryOperator( anyOf(hasOperatorName("+"), hasOperatorName("-"), hasOperatorName("+="), hasOperatorName("-=")), hasType(pointerType()), unless(hasLHS(ignoringImpCasts(declRefExpr(to(isImplicit())))))) .bind("expr"), this); Finder->addMatcher( unaryOperator(anyOf(hasOperatorName("++"), hasOperatorName("--")), hasType(pointerType())) .bind("expr"), this); // Array subscript on a pointer (not an array) is also pointer arithmetic Finder->addMatcher( arraySubscriptExpr( hasBase(ignoringImpCasts( anyOf(hasType(pointerType()), hasType(decayedType(hasDecayedType(pointerType()))))))) .bind("expr"), this); }
void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher( methodDecl(anyOf(constructorDecl(), hasOverloadedOperatorName("=")), unless(isImplicit()), unless(isDeleted())) .bind("decl"), this); }
void AssignOperatorSignatureCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (getLangOpts().CPlusPlus) { const auto HasGoodReturnType = methodDecl(returns(lValueReferenceType( pointee(unless(isConstQualified()), hasDeclaration(equalsBoundNode("class")))))); const auto IsSelf = qualType(anyOf( hasDeclaration(equalsBoundNode("class")), referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); const auto IsSelfAssign = methodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), hasName("operator="), ofClass(recordDecl().bind("class")), hasParameter(0, parmVarDecl(hasType(IsSelf)))) .bind("method"); Finder->addMatcher( methodDecl(IsSelfAssign, unless(HasGoodReturnType)).bind("ReturnType"), this); const auto BadSelf = referenceType( anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), rValueReferenceType(pointee(isConstQualified())))); Finder->addMatcher( methodDecl(IsSelfAssign, hasParameter(0, parmVarDecl(hasType(BadSelf)))) .bind("ArgumentType"), this); Finder->addMatcher(methodDecl(IsSelfAssign, isConst()).bind("Const"), this); } }
void RedundantVoidArgCheck::registerMatchers(MatchFinder *Finder) { Finder->addMatcher(functionDecl(parameterCountIs(0), unless(isImplicit()), unless(isExternC())) .bind(FunctionId), this); Finder->addMatcher(typedefNameDecl().bind(TypedefId), this); auto ParenFunctionType = parenType(innerType(functionType())); auto PointerToFunctionType = pointee(ParenFunctionType); auto FunctionOrMemberPointer = anyOf(hasType(pointerType(PointerToFunctionType)), hasType(memberPointerType(PointerToFunctionType))); Finder->addMatcher(fieldDecl(FunctionOrMemberPointer).bind(FieldId), this); Finder->addMatcher(varDecl(FunctionOrMemberPointer).bind(VarId), this); auto CastDestinationIsFunction = hasDestinationType(pointsTo(ParenFunctionType)); Finder->addMatcher( cStyleCastExpr(CastDestinationIsFunction).bind(CStyleCastId), this); Finder->addMatcher( cxxStaticCastExpr(CastDestinationIsFunction).bind(NamedCastId), this); Finder->addMatcher( cxxReinterpretCastExpr(CastDestinationIsFunction).bind(NamedCastId), this); Finder->addMatcher( cxxConstCastExpr(CastDestinationIsFunction).bind(NamedCastId), this); Finder->addMatcher(lambdaExpr().bind(LambdaId), this); }
void ExplicitConstructorCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; Finder->addMatcher( cxxConstructorDecl(unless(anyOf(isImplicit(), // Compiler-generated. isDeleted(), isInstantiated()))) .bind("ctor"), this); Finder->addMatcher( cxxConversionDecl(unless(anyOf(isExplicit(), // Already marked explicit. isImplicit(), // Compiler-generated. isDeleted(), isInstantiated()))) .bind("conversion"), this); }
void SpecialMemberFunctionsCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; Finder->addMatcher( cxxRecordDecl( eachOf( has(cxxDestructorDecl(unless(isImplicit())).bind("dtor")), has(cxxConstructorDecl(isCopyConstructor(), unless(isImplicit())) .bind("copy-ctor")), has(cxxMethodDecl(isCopyAssignmentOperator(), unless(isImplicit())) .bind("copy-assign")), has(cxxConstructorDecl(isMoveConstructor(), unless(isImplicit())) .bind("move-ctor")), has(cxxMethodDecl(isMoveAssignmentOperator(), unless(isImplicit())) .bind("move-assign")))) .bind("class-def"), this); }
void VirtualNearMissCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; Finder->addMatcher( cxxMethodDecl( unless(anyOf(isOverride(), isImplicit(), cxxConstructorDecl(), cxxDestructorDecl(), cxxConversionDecl(), isStatic(), isOverloadedOperator()))) .bind("method"), this); }
void NoexceptMoveConstructorCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus11) return; Finder->addMatcher( cxxMethodDecl(anyOf(cxxConstructorDecl(), hasOverloadedOperatorName("=")), unless(isImplicit()), unless(isDeleted())) .bind("decl"), this); }
void UnconventionalAssignOperatorCheck::registerMatchers( ast_matchers::MatchFinder *Finder) { // Only register the matchers for C++; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus) return; const auto HasGoodReturnType = cxxMethodDecl(returns(lValueReferenceType( pointee(unless(isConstQualified()), anyOf(autoType(), hasDeclaration(equalsBoundNode("class"))))))); const auto IsSelf = qualType( anyOf(hasDeclaration(equalsBoundNode("class")), referenceType(pointee(hasDeclaration(equalsBoundNode("class")))))); const auto IsAssign = cxxMethodDecl(unless(anyOf(isDeleted(), isPrivate(), isImplicit())), hasName("operator="), ofClass(recordDecl().bind("class"))) .bind("method"); const auto IsSelfAssign = cxxMethodDecl(IsAssign, hasParameter(0, parmVarDecl(hasType(IsSelf)))) .bind("method"); Finder->addMatcher( cxxMethodDecl(IsAssign, unless(HasGoodReturnType)).bind("ReturnType"), this); const auto BadSelf = referenceType( anyOf(lValueReferenceType(pointee(unless(isConstQualified()))), rValueReferenceType(pointee(isConstQualified())))); Finder->addMatcher( cxxMethodDecl(IsSelfAssign, hasParameter(0, parmVarDecl(hasType(BadSelf)))) .bind("ArgumentType"), this); Finder->addMatcher( cxxMethodDecl(IsSelfAssign, anyOf(isConst(), isVirtual())).bind("cv"), this); const auto IsBadReturnStatement = returnStmt(unless(has(ignoringParenImpCasts( anyOf(unaryOperator(hasOperatorName("*"), hasUnaryOperand(cxxThisExpr())), cxxOperatorCallExpr(argumentCountIs(1), callee(unresolvedLookupExpr()), hasArgument(0, cxxThisExpr()))))))); const auto IsGoodAssign = cxxMethodDecl(IsAssign, HasGoodReturnType); Finder->addMatcher(returnStmt(IsBadReturnStatement, forFunction(IsGoodAssign)) .bind("returnStmt"), this); }
void QTreeValidator::determineProc(idx_t & idx, ArgType & type, const std::string & input, const std::vector<std::string>& synList, bool hasImplicit) { determineArgIdxType(idx, type, input, synList); if (ArgType::NOT_SPECIFIED == type) { if (hasImplicit && isImplicit(input)) { idx = ARG_IDX_NOT_SPECIFIED; type = ArgType::IMPLICIT; } else { idx = determineConstProc(input); type = ArgType::CONST; } } }
void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not // provide any benefit to other languages, despite being benign. if (getLangOpts().CPlusPlus11) { Finder->addMatcher( constructorDecl(unless(isImplicit()), allOf( isMoveConstructor(), hasAnyConstructorInitializer( ctorInitializer(withInitializer(constructExpr(hasDeclaration( constructorDecl(isCopyConstructor()).bind("ctor") )))).bind("init") ) )), this); } }
void MoveConstructorInitCheck::registerMatchers(MatchFinder *Finder) { // Only register the matchers for C++11; the functionality currently does not // provide any benefit to other languages, despite being benign. if (!getLangOpts().CPlusPlus11) return; Finder->addMatcher( cxxConstructorDecl( unless(isImplicit()), allOf(isMoveConstructor(), hasAnyConstructorInitializer( cxxCtorInitializer( withInitializer(cxxConstructExpr(hasDeclaration( cxxConstructorDecl(isCopyConstructor()) .bind("ctor"))))) .bind("move-init")))), this); auto NonConstValueMovableAndExpensiveToCopy = qualType(allOf(unless(pointerType()), unless(isConstQualified()), hasDeclaration(cxxRecordDecl(hasMethod(cxxConstructorDecl( isMoveConstructor(), unless(isDeleted()))))), matchers::isExpensiveToCopy())); // This checker is also used to implement cert-oop11-cpp, but when using that // form of the checker, we do not want to diagnose movable parameters. if (!UseCERTSemantics) { Finder->addMatcher( cxxConstructorDecl( allOf( unless(isMoveConstructor()), hasAnyConstructorInitializer(withInitializer(cxxConstructExpr( hasDeclaration(cxxConstructorDecl(isCopyConstructor())), hasArgument( 0, declRefExpr( to(parmVarDecl( hasType( NonConstValueMovableAndExpensiveToCopy)) .bind("movable-param"))) .bind("init-arg"))))))) .bind("ctor-decl"), this); } }
Real CHInterface::computeQpJacobian() { //Actual value to return Real value = 0.0; if (isImplicit()) { value = _kappa[_qp] * _second_phi[_j][_qp].tr() * (_M[_qp] * _second_test[_i][_qp].tr() + _grad_M[_qp]*_grad_test[_i][_qp]); if (_has_MJac) { RealGradient full_Dgrad_M = _grad_phi[_j][_qp] * (*_Dgrad_Mngp)[_qp] + _phi[_j][_qp] * (*_Dgrad_Mnp)[_qp]; value += _kappa[_qp] * _second_u[_qp].tr() * ((*_DM)[_qp] * _phi[_j][_qp] * _second_test[_i][_qp].tr() + full_Dgrad_M * _grad_test[_i][_qp]); } } return value; }
void QTreeValidator::validatePTClause(QueryData & queryData, PTClauseEntry * ptClausePtr, const std::vector<std::string>& synList) { QEvalPTClause *evalPtClause = new QEvalPTClause(); evalPtClause->ptType = ptClausePtr->getPatternType(); idx_t tmpIdx = getVarArgIdx(synList, ptClausePtr->getSynonym()); assert(ARG_IDX_NOT_FOUND != tmpIdx); assert(isDecArgStmtType(queryData.getVarDecType(tmpIdx))); evalPtClause->stmt = tmpIdx; determineVar(evalPtClause->var, evalPtClause->varArgType, ptClausePtr->getFirstParameter(), synList, true); if (evalPtClause->ptType == PTClauseType::PT_Assign) { std::string patternStr = ptClausePtr->getSecondParameter(); if (isImplicit(patternStr)) { evalPtClause->pattern = ""; evalPtClause->completeMatch = false; } else if (isDoubleQuoted(patternStr)) { evalPtClause->pattern = dropDoubleQuote(patternStr); evalPtClause->completeMatch = true; } else if (isUnderlineDoubleQuoted(patternStr)) { evalPtClause->pattern = dropUnderlineDoubleQuote(patternStr); evalPtClause->completeMatch = false; } else { assert(false); } } evalPtClause->inVarArgIdxSet.insert(evalPtClause->stmt); if (ArgType::DECVAR == evalPtClause->varArgType) { evalPtClause->inVarArgIdxSet.insert(evalPtClause->var); } queryData.appendQEvalClause(evalPtClause); }
void FunctionNamingCheck::registerMatchers(MatchFinder *Finder) { // This check should only be applied to Objective-C sources. if (!getLangOpts().ObjC) return; // Enforce Objective-C function naming conventions on all functions except: // • Functions defined in system headers. // • C++ member functions. // • Namespaced functions. // • Implicitly defined functions. // • The main function. Finder->addMatcher( functionDecl( unless(anyOf(isExpansionInSystemHeader(), cxxMethodDecl(), hasAncestor(namespaceDecl()), isMain(), isImplicit(), matchesName(validFunctionNameRegex(true)), allOf(isStaticStorageClass(), matchesName(validFunctionNameRegex(false)))))) .bind("function"), this); }
void NewDeleteOverloadsCheck::registerMatchers(MatchFinder *Finder) { if (!getLangOpts().CPlusPlus) return; // Match all operator new and operator delete overloads (including the array // forms). Do not match implicit operators, placement operators, or // deleted/private operators. // // Technically, trivially-defined operator delete seems like a reasonable // thing to also skip. e.g., void operator delete(void *) {} // However, I think it's more reasonable to warn in this case as the user // should really be writing that as a deleted function. Finder->addMatcher( functionDecl(unless(anyOf(isImplicit(), isPlacementOverload(), isDeleted(), cxxMethodDecl(isPrivate()))), anyOf(hasOverloadedOperatorName("new"), hasOverloadedOperatorName("new[]"), hasOverloadedOperatorName("delete"), hasOverloadedOperatorName("delete[]"))) .bind("func"), this); }
void IndexerJob::handleReference(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { const CXCursorKind refKind = clang_getCursorKind(ref); if (clang_isInvalid(refKind)) { superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, parent); return; } bool isOperator = false; if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod || refKind == CXCursor_ConversionFunction || refKind == CXCursor_FunctionDecl || refKind == CXCursor_FunctionTemplate)) { // these are bullshit, for this construct: // foo.bar(); // the position of the cursor is at the foo, not the bar. // They are not interesting for followLocation, renameSymbol or find // references so we toss them. // For functions it can be the position of the namespace. // E.g. Foo::bar(); cursor is on Foo // For constructors they happen to be the only thing we have that // actually refs the constructor and not the class so we have to keep // them for that. return; } switch (refKind) { case CXCursor_Constructor: if (isImplicit(ref)) return; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: { CXStringScope scope = clang_getCursorDisplayName(ref); const char *data = scope.data(); if (data) { const int len = strlen(data); if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { if (isImplicit(ref)) return; // eat implicit operator calls isOperator = true; } } break; } default: break; } const Location reffedLoc = createLocation(ref, 0); if (!reffedLoc.isValid()) return; CursorInfo &refInfo = mData->symbols[reffedLoc]; if (!refInfo.symbolLength && !handleCursor(ref, refKind, reffedLoc)) return; refInfo.references.insert(location); CursorInfo &info = mData->symbols[location]; info.targets.insert(reffedLoc); // We need the new cursor to replace the symbolLength. This is important // in the following case: // struct R { R(const &r); ... } // R foo(); // ... // R r = foo(); // The first cursor on foo() will be a reference to the copy constructor and // this cursor will have a symbolLength of 1. Thus you won't be able to jump // to foo from the o. This is fixed by making sure the newer target, if // better, gets to decide on the symbolLength // The !isCursor is var decls and field decls where we set up a target even // if they're not considered references if (!RTags::isCursor(info.kind) && (!info.symbolLength || info.bestTarget(mData->symbols).kind == refKind)) { CXSourceRange range = clang_getCursorExtent(cursor); unsigned start, end; clang_getSpellingLocation(clang_getRangeStart(range), 0, 0, 0, &start); clang_getSpellingLocation(clang_getRangeEnd(range), 0, 0, 0, &end); info.start = start; info.end = end; info.definition = false; info.kind = kind; info.symbolLength = isOperator ? end - start : refInfo.symbolLength; info.symbolName = refInfo.symbolName; info.type = clang_getCursorType(cursor).kind; switch (kind) { case CXCursor_CallExpr: nestedClassConstructorCallUgleHack(parent, info, refKind, reffedLoc); // see rtags/tests/nestedClassConstructorCallUgleHack/ break; default: break; } } Set<Location> &val = mData->references[location]; val.insert(reffedLoc); }
void ClangIndexer::handleReference(const CXCursor &cursor, CXCursorKind kind, const Location &location, const CXCursor &ref, const CXCursor &parent) { const CXCursorKind refKind = clang_getCursorKind(ref); if (clang_isInvalid(refKind)) { superclassTemplateMemberFunctionUgleHack(cursor, kind, location, ref, parent); return; } bool isOperator = false; if (kind == CXCursor_CallExpr && (refKind == CXCursor_CXXMethod || refKind == CXCursor_ConversionFunction || refKind == CXCursor_FunctionDecl || refKind == CXCursor_FunctionTemplate)) { // these are bullshit, for this construct: // foo.bar(); // the position of the cursor is at the foo, not the bar. // They are not interesting for followLocation, renameSymbol or find // references so we toss them. // For functions it can be the position of the namespace. // E.g. Foo::bar(); cursor is on Foo // For constructors they happen to be the only thing we have that // actually refs the constructor and not the class so we have to keep // them for that. return; } switch (refKind) { case CXCursor_Constructor: if (isImplicit(ref)) return; break; case CXCursor_CXXMethod: case CXCursor_FunctionDecl: case CXCursor_FunctionTemplate: { CXStringScope scope = clang_getCursorDisplayName(ref); const char *data = scope.data(); if (data) { const int len = strlen(data); if (len > 8 && !strncmp(data, "operator", 8) && !isalnum(data[8]) && data[8] != '_') { if (isImplicit(ref)) return; // eat implicit operator calls isOperator = true; } } break; } default: break; } const Location reffedLoc = createLocation(ref); if (!reffedLoc.isValid()) { if (kind == CXCursor_ObjCMessageExpr) { mData->pendingReferenceMap[RTags::eatString(clang_getCursorUSR(clang_getCanonicalCursor(ref)))].insert(location); // insert it, we'll hook up the target and references later handleCursor(cursor, kind, location); } return; } std::shared_ptr<CursorInfo> &refInfo = mData->symbols[reffedLoc]; if ((!refInfo || !refInfo->symbolLength) && !handleCursor(ref, refKind, reffedLoc)) return; refInfo->references.insert(location); std::shared_ptr<CursorInfo> &info = mData->symbols[location]; if (!info) info = std::make_shared<CursorInfo>(); info->targets.insert(reffedLoc); // We need the new cursor to replace the symbolLength. This is important // in the following case: // struct R { R(const &r); ... } // R foo(); // ... // R r = foo(); // The first cursor on foo() will be a reference to the copy constructor and // this cursor will have a symbolLength of 1. Thus you won't be able to jump // to foo from the o. This is fixed by making sure the newer target, if // better, gets to decide on the symbolLength // The !isCursor is var decls and field decls where we set up a target even // if they're not considered references if (!RTags::isCursor(info->kind) && (!info->symbolLength || info->bestTarget(mData->symbols)->kind == refKind)) { CXSourceRange range = clang_getCursorExtent(cursor); CXSourceLocation rangeStart = clang_getRangeStart(range); CXSourceLocation rangeEnd = clang_getRangeEnd(range); unsigned startLine, startColumn, endLine, endColumn; clang_getPresumedLocation(rangeStart, 0, &startLine, &startColumn); clang_getPresumedLocation(rangeEnd, 0, &endLine, &endColumn); info->startLine = startLine; info->startColumn = startColumn; info->endLine = endLine; info->endColumn = endColumn; info->definition = false; info->kind = kind; if (isOperator) { unsigned start, end; clang_getSpellingLocation(rangeStart, 0, 0, 0, &start); clang_getSpellingLocation(rangeEnd, 0, 0, 0, &end); info->symbolLength = end - start; } else { info->symbolLength = refInfo->symbolLength; } info->symbolName = refInfo->symbolName; info->type = clang_getCursorType(cursor).kind; } }
bool DeclReferencer::Reference(const clang::NamedDecl *D) { if (D->isInvalidDecl()) return true; for (const clang::Decl *DI = D; !isa<clang::TranslationUnitDecl>(DI); DI = cast<clang::Decl>(DI->getDeclContext())) if (auto RD = dyn_cast<clang::CXXRecordDecl>(DI)) if (RD->isLocalClass()) return true; // are local records emitted when emitting a function? if no this is a FIXME if (auto VD = dyn_cast<clang::VarDecl>(D)) if (!VD->isFileVarDecl()) return true; if (auto FD = dyn_cast<clang::FunctionDecl>(D)) { if (!isMapped(D)) return true; if (FD->getBuiltinID() || (FD->isOverloadedOperator() && FD->isImplicit())) return true; if (FD->isExternC()) return true; // FIXME: Clang 3.6 doesn't always map decls to the right source file, // so the path generated by typeQualifiedFor although correct will result in a failed lookup. // This may get fixed by 3.7. } if (Referenced.count(D->getCanonicalDecl())) return true; Referenced.insert(D->getCanonicalDecl()); // Although we try to add all the needed imports during importAll(), sometimes we miss a module so ensure it gets loaded auto im = mapper.AddImplicitImportForDecl(loc, D, true); im->isstatic = true; auto dst = Package::resolve(im->packages, NULL, &im->pkg); if (!dst->lookup(im->id)) { im->semantic(sc); im->semantic2(sc); } ReferenceTemplateArguments(D); auto Func = dyn_cast<clang::FunctionDecl>(D); if (Func && Func->getPrimaryTemplate()) D = cast<clang::NamedDecl>(getCanonicalDecl(getSpecializedDeclOrExplicit(Func))); // HACK FIXME if (Func && Func->isOutOfLine() && Func->getFriendObjectKind() != clang::Decl::FOK_None) { auto Pattern = Func; if (auto MemberFunc = Func->getInstantiatedFromMemberFunction()) Pattern = MemberFunc; if (Pattern->isDependentContext()) return true; } auto e = expmap.fromExpressionDeclRef(loc, const_cast<clang::NamedDecl*>(D), nullptr, TQ_OverOpSkipSpecArg); e = e->semantic(sc); if (Func && Func->getPrimaryTemplate()) { assert(e->op == TOKvar || e->op == TOKtemplate || e->op == TOKimport); Dsymbol *s; if (e->op == TOKvar) s = static_cast<SymbolExp*>(e)->var; else if (e->op == TOKtemplate) s = static_cast<TemplateExp*>(e)->td; else s = static_cast<ScopeExp*>(e)->sds; // if it's a non-template function there's nothing to do, it will be semantic'd along with its declcontext // if it's a template spec we must instantiate the right overload struct DEquals { const clang::Decl* D; Dsymbol *s = nullptr; // return value static int fp(void *param, Dsymbol *s) { if (!isCPP(s)) return 0; auto fd = s->isFuncDeclaration(); auto td = static_cast<cpp::TemplateDeclaration*>( s->isTemplateDeclaration()); DEquals *p = (DEquals *)param; decltype(D) s_D = fd ? getFD(fd) : td->TempOrSpec; if (p->D == getCanonicalDecl(s_D)) { p->s = s; return 1; } return 0; } }; DEquals p; p.D = D; overloadApply(s, &p, &DEquals::fp); assert(p.s && p.s->isTemplateDeclaration()); auto td = static_cast<cpp::TemplateDeclaration*>(p.s->isTemplateDeclaration()); if (td->semanticRun == PASSinit) { assert(td->scope); td->semantic(td->scope); // this must be done here because havetempdecl being set to true it won't be done by findTempDecl() assert(td->semanticRun > PASSinit); } auto tiargs = mapper.fromTemplateArguments(loc, Func->getTemplateSpecializationArgs()); assert(tiargs); SpecValue spec(mapper); getIdentifier(Func, &spec, true); if (spec) tiargs->shift(spec.toTemplateArg(loc)); auto tempinst = new cpp::TemplateInstance(loc, td, tiargs); tempinst->Inst = const_cast<clang::FunctionDecl*>(Func); tempinst->semantictiargsdone = false; // NOTE: the "havetempdecl" ctor of Templateinstance set semantictiargsdone to true... // Time was lost finding this out for the second or third time. td->makeForeignInstance(tempinst); tempinst->semantic(sc); } // Memory usage can skyrocket when using a large library if (im->packages) delete im->packages; delete im; delete e; return true; }
void InconsistentDeclarationParameterNameCheck::registerMatchers( MatchFinder *Finder) { Finder->addMatcher(functionDecl(unless(isImplicit()), hasOtherDeclarations()) .bind("functionDecl"), this); }
bool ButcherTable::isExplicit() const{ return !isImplicit(); }