diff options
Diffstat (limited to 'lib/ASTMatchers/Dynamic/Registry.cpp')
-rw-r--r-- | lib/ASTMatchers/Dynamic/Registry.cpp | 211 |
1 files changed, 190 insertions, 21 deletions
diff --git a/lib/ASTMatchers/Dynamic/Registry.cpp b/lib/ASTMatchers/Dynamic/Registry.cpp index 70e956e65465..4bc50a0f2a96 100644 --- a/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/lib/ASTMatchers/Dynamic/Registry.cpp @@ -13,23 +13,24 @@ //===------------------------------------------------------------===// #include "clang/ASTMatchers/Dynamic/Registry.h" - -#include <utility> - #include "Marshallers.h" #include "clang/ASTMatchers/ASTMatchers.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/ManagedStatic.h" +#include <set> +#include <utility> + +using namespace clang::ast_type_traits; namespace clang { namespace ast_matchers { namespace dynamic { namespace { -using internal::MatcherCreateCallback; +using internal::MatcherDescriptor; -typedef llvm::StringMap<const MatcherCreateCallback *> ConstructorMap; +typedef llvm::StringMap<const MatcherDescriptor *> ConstructorMap; class RegistryMaps { public: RegistryMaps(); @@ -38,12 +39,12 @@ public: const ConstructorMap &constructors() const { return Constructors; } private: - void registerMatcher(StringRef MatcherName, MatcherCreateCallback *Callback); + void registerMatcher(StringRef MatcherName, MatcherDescriptor *Callback); ConstructorMap Constructors; }; void RegistryMaps::registerMatcher(StringRef MatcherName, - MatcherCreateCallback *Callback) { + MatcherDescriptor *Callback) { assert(Constructors.find(MatcherName) == Constructors.end()); Constructors[MatcherName] = Callback; } @@ -58,14 +59,14 @@ void RegistryMaps::registerMatcher(StringRef MatcherName, #define REGISTER_OVERLOADED_2(name) \ do { \ - MatcherCreateCallback *Callbacks[] = { \ + MatcherDescriptor *Callbacks[] = { \ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 0), \ #name), \ internal::makeMatcherAutoMarshall(SPECIFIC_MATCHER_OVERLOAD(name, 1), \ #name) \ }; \ registerMatcher(#name, \ - new internal::OverloadedMatcherCreateCallback(Callbacks)); \ + new internal::OverloadedMatcherDescriptor(Callbacks)); \ } while (0) /// \brief Generate a registry map with all the known matchers. @@ -76,11 +77,9 @@ RegistryMaps::RegistryMaps() { // ofKind // // Polymorphic + argument overload: - // unless // findAll // // Other: - // loc // equals // equalsNode @@ -89,6 +88,7 @@ RegistryMaps::RegistryMaps() { REGISTER_OVERLOADED_2(hasType); REGISTER_OVERLOADED_2(isDerivedFrom); REGISTER_OVERLOADED_2(isSameOrDerivedFrom); + REGISTER_OVERLOADED_2(loc); REGISTER_OVERLOADED_2(pointsTo); REGISTER_OVERLOADED_2(references); REGISTER_OVERLOADED_2(thisPointerType); @@ -113,6 +113,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(builtinType); REGISTER_MATCHER(cStyleCastExpr); REGISTER_MATCHER(callExpr); + REGISTER_MATCHER(caseStmt); REGISTER_MATCHER(castExpr); REGISTER_MATCHER(catchStmt); REGISTER_MATCHER(characterLiteral); @@ -133,7 +134,9 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(declCountIs); REGISTER_MATCHER(declRefExpr); REGISTER_MATCHER(declStmt); + REGISTER_MATCHER(declaratorDecl); REGISTER_MATCHER(defaultArgExpr); + REGISTER_MATCHER(defaultStmt); REGISTER_MATCHER(deleteExpr); REGISTER_MATCHER(dependentSizedArrayType); REGISTER_MATCHER(destructorDecl); @@ -143,15 +146,20 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(elaboratedType); REGISTER_MATCHER(enumConstantDecl); REGISTER_MATCHER(enumDecl); + REGISTER_MATCHER(equalsBoundNode); REGISTER_MATCHER(explicitCastExpr); REGISTER_MATCHER(expr); + REGISTER_MATCHER(exprWithCleanups); REGISTER_MATCHER(fieldDecl); REGISTER_MATCHER(floatLiteral); REGISTER_MATCHER(forEach); + REGISTER_MATCHER(forEachConstructorInitializer); REGISTER_MATCHER(forEachDescendant); + REGISTER_MATCHER(forEachSwitchCase); REGISTER_MATCHER(forField); REGISTER_MATCHER(forRangeStmt); REGISTER_MATCHER(forStmt); + REGISTER_MATCHER(friendDecl); REGISTER_MATCHER(functionDecl); REGISTER_MATCHER(functionTemplateDecl); REGISTER_MATCHER(functionType); @@ -170,6 +178,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasBase); REGISTER_MATCHER(hasBody); REGISTER_MATCHER(hasCanonicalType); + REGISTER_MATCHER(hasCaseConstant); REGISTER_MATCHER(hasCondition); REGISTER_MATCHER(hasConditionVariableStatement); REGISTER_MATCHER(hasDeclContext); @@ -180,12 +189,14 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasEitherOperand); REGISTER_MATCHER(hasElementType); REGISTER_MATCHER(hasFalseExpression); + REGISTER_MATCHER(hasGlobalStorage); REGISTER_MATCHER(hasImplicitDestinationType); REGISTER_MATCHER(hasIncrement); REGISTER_MATCHER(hasIndex); REGISTER_MATCHER(hasInitializer); REGISTER_MATCHER(hasLHS); REGISTER_MATCHER(hasLocalQualifiers); + REGISTER_MATCHER(hasLocalStorage); REGISTER_MATCHER(hasLoopInit); REGISTER_MATCHER(hasMethod); REGISTER_MATCHER(hasName); @@ -203,6 +214,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(hasTargetDecl); REGISTER_MATCHER(hasTemplateArgument); REGISTER_MATCHER(hasTrueExpression); + REGISTER_MATCHER(hasTypeLoc); REGISTER_MATCHER(hasUnaryOperand); REGISTER_MATCHER(hasValueType); REGISTER_MATCHER(ifStmt); @@ -215,12 +227,15 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(innerType); REGISTER_MATCHER(integerLiteral); REGISTER_MATCHER(isArrow); + REGISTER_MATCHER(isConst); REGISTER_MATCHER(isConstQualified); REGISTER_MATCHER(isDefinition); REGISTER_MATCHER(isExplicitTemplateSpecialization); + REGISTER_MATCHER(isExpr); REGISTER_MATCHER(isExternC); REGISTER_MATCHER(isImplicit); REGISTER_MATCHER(isInteger); + REGISTER_MATCHER(isListInitialization); REGISTER_MATCHER(isOverride); REGISTER_MATCHER(isPrivate); REGISTER_MATCHER(isProtected); @@ -252,6 +267,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(operatorCallExpr); REGISTER_MATCHER(parameterCountIs); REGISTER_MATCHER(parenType); + REGISTER_MATCHER(parmVarDecl); REGISTER_MATCHER(pointee); REGISTER_MATCHER(pointerType); REGISTER_MATCHER(qualType); @@ -275,6 +291,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(switchCase); REGISTER_MATCHER(switchStmt); REGISTER_MATCHER(templateSpecializationType); + REGISTER_MATCHER(temporaryObjectExpr); REGISTER_MATCHER(thisExpr); REGISTER_MATCHER(throughUsingDecl); REGISTER_MATCHER(throwExpr); @@ -285,6 +302,10 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(typedefType); REGISTER_MATCHER(unaryExprOrTypeTraitExpr); REGISTER_MATCHER(unaryOperator); + REGISTER_MATCHER(unaryTransformType); + REGISTER_MATCHER(unless); + REGISTER_MATCHER(unresolvedConstructExpr); + REGISTER_MATCHER(unresolvedUsingValueDecl); REGISTER_MATCHER(userDefinedLiteral); REGISTER_MATCHER(usingDecl); REGISTER_MATCHER(varDecl); @@ -306,27 +327,175 @@ static llvm::ManagedStatic<RegistryMaps> RegistryData; } // anonymous namespace // static -VariantMatcher Registry::constructMatcher(StringRef MatcherName, - const SourceRange &NameRange, - ArrayRef<ParserValue> Args, - Diagnostics *Error) { +llvm::Optional<MatcherCtor> Registry::lookupMatcherCtor(StringRef MatcherName) { ConstructorMap::const_iterator it = RegistryData->constructors().find(MatcherName); - if (it == RegistryData->constructors().end()) { - Error->addError(NameRange, Error->ET_RegistryNotFound) << MatcherName; - return VariantMatcher(); + return it == RegistryData->constructors().end() + ? llvm::Optional<MatcherCtor>() + : it->second; +} + +namespace { + +llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, + const std::set<ASTNodeKind> &KS) { + unsigned Count = 0; + for (std::set<ASTNodeKind>::const_iterator I = KS.begin(), E = KS.end(); + I != E; ++I) { + if (I != KS.begin()) + OS << "|"; + if (Count++ == 3) { + OS << "..."; + break; + } + OS << *I; + } + return OS; +} + +struct ReverseSpecificityThenName { + bool operator()(const std::pair<unsigned, std::string> &A, + const std::pair<unsigned, std::string> &B) const { + return A.first > B.first || (A.first == B.first && A.second < B.second); } +}; + +} + +std::vector<MatcherCompletion> Registry::getCompletions( + ArrayRef<std::pair<MatcherCtor, unsigned> > Context) { + ASTNodeKind InitialTypes[] = { + ASTNodeKind::getFromNodeKind<Decl>(), + ASTNodeKind::getFromNodeKind<QualType>(), + ASTNodeKind::getFromNodeKind<Type>(), + ASTNodeKind::getFromNodeKind<Stmt>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifier>(), + ASTNodeKind::getFromNodeKind<NestedNameSpecifierLoc>(), + ASTNodeKind::getFromNodeKind<TypeLoc>() + }; + ArrayRef<ASTNodeKind> InitialTypesRef(InitialTypes); - return it->second->run(NameRange, Args, Error); + // Starting with the above seed of acceptable top-level matcher types, compute + // the acceptable type set for the argument indicated by each context element. + std::set<ASTNodeKind> TypeSet(InitialTypesRef.begin(), InitialTypesRef.end()); + for (ArrayRef<std::pair<MatcherCtor, unsigned> >::iterator + CtxI = Context.begin(), + CtxE = Context.end(); + CtxI != CtxE; ++CtxI) { + std::vector<internal::ArgKind> NextTypeSet; + for (std::set<ASTNodeKind>::iterator I = TypeSet.begin(), E = TypeSet.end(); + I != E; ++I) { + if (CtxI->first->isConvertibleTo(*I) && + (CtxI->first->isVariadic() || + CtxI->second < CtxI->first->getNumArgs())) + CtxI->first->getArgKinds(*I, CtxI->second, NextTypeSet); + } + TypeSet.clear(); + for (std::vector<internal::ArgKind>::iterator I = NextTypeSet.begin(), + E = NextTypeSet.end(); + I != E; ++I) { + if (I->getArgKind() == internal::ArgKind::AK_Matcher) + TypeSet.insert(I->getMatcherKind()); + } + } + + typedef std::map<std::pair<unsigned, std::string>, MatcherCompletion, + ReverseSpecificityThenName> CompletionsTy; + CompletionsTy Completions; + + // TypeSet now contains the list of acceptable types for the argument we are + // completing. Search the registry for acceptable matchers. + for (ConstructorMap::const_iterator I = RegistryData->constructors().begin(), + E = RegistryData->constructors().end(); + I != E; ++I) { + std::set<ASTNodeKind> RetKinds; + unsigned NumArgs = I->second->isVariadic() ? 1 : I->second->getNumArgs(); + bool IsPolymorphic = I->second->isPolymorphic(); + std::vector<std::vector<internal::ArgKind> > ArgsKinds(NumArgs); + unsigned MaxSpecificity = 0; + for (std::set<ASTNodeKind>::iterator TI = TypeSet.begin(), + TE = TypeSet.end(); + TI != TE; ++TI) { + unsigned Specificity; + ASTNodeKind LeastDerivedKind; + if (I->second->isConvertibleTo(*TI, &Specificity, &LeastDerivedKind)) { + if (MaxSpecificity < Specificity) + MaxSpecificity = Specificity; + RetKinds.insert(LeastDerivedKind); + for (unsigned Arg = 0; Arg != NumArgs; ++Arg) + I->second->getArgKinds(*TI, Arg, ArgsKinds[Arg]); + if (IsPolymorphic) + break; + } + } + + if (!RetKinds.empty() && MaxSpecificity > 0) { + std::string Decl; + llvm::raw_string_ostream OS(Decl); + + if (IsPolymorphic) { + OS << "Matcher<T> " << I->first() << "(Matcher<T>"; + } else { + OS << "Matcher<" << RetKinds << "> " << I->first() << "("; + for (std::vector<std::vector<internal::ArgKind> >::iterator + KI = ArgsKinds.begin(), + KE = ArgsKinds.end(); + KI != KE; ++KI) { + if (KI != ArgsKinds.begin()) + OS << ", "; + // This currently assumes that a matcher may not overload a + // non-matcher, and all non-matcher overloads have identical + // arguments. + if ((*KI)[0].getArgKind() == internal::ArgKind::AK_Matcher) { + std::set<ASTNodeKind> MatcherKinds; + std::transform( + KI->begin(), KI->end(), + std::inserter(MatcherKinds, MatcherKinds.end()), + std::mem_fun_ref(&internal::ArgKind::getMatcherKind)); + OS << "Matcher<" << MatcherKinds << ">"; + } else { + OS << (*KI)[0].asString(); + } + } + } + if (I->second->isVariadic()) + OS << "..."; + OS << ")"; + + std::string TypedText = I->first(); + TypedText += "("; + if (ArgsKinds.empty()) + TypedText += ")"; + else if (ArgsKinds[0][0].getArgKind() == internal::ArgKind::AK_String) + TypedText += "\""; + + Completions[std::make_pair(MaxSpecificity, I->first())] = + MatcherCompletion(TypedText, OS.str()); + } + } + + std::vector<MatcherCompletion> RetVal; + for (CompletionsTy::iterator I = Completions.begin(), E = Completions.end(); + I != E; ++I) + RetVal.push_back(I->second); + return RetVal; +} + +// static +VariantMatcher Registry::constructMatcher(MatcherCtor Ctor, + const SourceRange &NameRange, + ArrayRef<ParserValue> Args, + Diagnostics *Error) { + return Ctor->create(NameRange, Args, Error); } // static -VariantMatcher Registry::constructBoundMatcher(StringRef MatcherName, +VariantMatcher Registry::constructBoundMatcher(MatcherCtor Ctor, const SourceRange &NameRange, StringRef BindID, ArrayRef<ParserValue> Args, Diagnostics *Error) { - VariantMatcher Out = constructMatcher(MatcherName, NameRange, Args, Error); + VariantMatcher Out = constructMatcher(Ctor, NameRange, Args, Error); if (Out.isNull()) return Out; llvm::Optional<DynTypedMatcher> Result = Out.getSingleMatcher(); |