Add support for lookup function from QualType(s).

Add new overload for findFunctionProto and matchFunctionProto which rather than
taking the list of argument types as a StringRef, take it as a
const llvm::SmallVector<clang::QualType, 4>.  This avoids the (permanent)
allocations inside clang due to the Parsing of types.
This commit is contained in:
Philippe Canal 2013-08-25 01:16:29 -05:00 committed by sftnight
parent 7312683eda
commit 467cb93b3e
3 changed files with 182 additions and 3 deletions

View File

@ -95,6 +95,21 @@ namespace cling {
llvm::StringRef funcArgs,
bool objectIsConst = false) const;
///\brief Lookup a function based on its Decl(Context), name and parameters.
///
///\param [in] scopeDecl - the scope (namespace or tag) that is searched for
/// the function.
///\param [in] funcName - the name of the function to find.
///\param [in] funcProto - the list of types of the function parameters
///\param [in] objectIsConst - if true search fo function that can
/// be called on a const object ; default to false.
///\returns The function found or null.
const clang::FunctionDecl* findFunctionProto(const clang::Decl* scopeDecl,
llvm::StringRef funcName,
const llvm::SmallVector<clang::QualType, 4>& funcProto,
bool objectIsConst = false
) const;
///\brief Lookup a function based on its Decl(Context), name and parameters.
/// where the result if any must have exactly the arguments requested.
@ -113,6 +128,21 @@ namespace cling {
bool objectIsConst
) const;
///\brief Lookup a function based on its Decl(Context), name and parameters.
/// where the result if any must have exactly the arguments requested.
///
///\param[in] scopeDecl - the scope (namespace or tag) that is searched for
/// the function.
///\param[in] funcName - the name of the function to find.
///\param[in] funcProto - the list of types of the function parameters
///\param[in] objectIsConst - if true search fo function that can
/// be called on a const object ; default to false.
///\returns The function found or null.
const clang::FunctionDecl* matchFunctionProto(const clang::Decl* scopeDecl,
llvm::StringRef funcName,
const llvm::SmallVector<clang::QualType, 4>& funcProto,
bool objectIsConst
) const;
///\brief Lookup given argument list and return each argument as an
/// expression.

View File

@ -825,7 +825,37 @@ namespace cling {
}
static
bool ParseProto(llvm::SmallVector<Expr*, 4> &GivenArgs,
bool getExprProto(llvm::SmallVector<ExprAlloc, 4> &ExprMemory,
llvm::SmallVector<Expr*, 4> &GivenArgs,
const llvm::SmallVector<QualType, 4> &GivenTypes) {
//
// Create the array of Expr from the array of Types.
//
typedef llvm::SmallVector<QualType, 4>::const_iterator iterator;
for(iterator iter = GivenTypes.begin(), end = GivenTypes.end();
iter != end;
++iter) {
const clang::QualType QT = iter->getCanonicalType();
{
ExprValueKind VK = VK_RValue;
if (QT->getAs<LValueReferenceType>()) {
VK = VK_LValue;
}
clang::QualType NonRefQT(QT.getNonReferenceType());
unsigned int slot = ExprMemory.size();
ExprMemory.resize(slot+1);
Expr* val = new (&ExprMemory[slot]) OpaqueValueExpr(SourceLocation(),
NonRefQT, VK);
GivenArgs.push_back(val);
}
}
return true;
}
static
bool ParseProto(llvm::SmallVector<ExprAlloc, 4> &ExprMemory,
llvm::SmallVector<Expr*, 4> &GivenArgs,
ASTContext& Context, Parser &P,Sema &S) {
//
// Parse the prototype now.
@ -875,6 +905,51 @@ namespace cling {
return true;
}
const FunctionDecl* LookupHelper::findFunctionProto(const Decl* scopeDecl,
llvm::StringRef funcName,
const llvm::SmallVector<QualType, 4>& funcProto,
bool objectIsConst
) const {
assert(scopeDecl && "Decl cannot be null");
//
// Some utilities.
//
// Use P for shortness
Parser& P = *m_Parser;
Sema& S = P.getActions();
ASTContext& Context = S.getASTContext();
//
// Convert the passed decl into a nested name specifier,
// a scope spec, and a decl context.
//
// Do this 'early' to save on the expansive parser setup,
// in case of failure.
//
CXXScopeSpec SS;
DeclContext* foundDC = getContextAndSpec(SS,scopeDecl,Context,S);
if (!foundDC) return 0;
llvm::SmallVector<ExprAlloc, 4> ExprMemory;
llvm::SmallVector<Expr*, 4> GivenArgs;
if (!funcProto.empty()) {
if (!getExprProto(ExprMemory, GivenArgs, funcProto) ) {
return 0;
}
}
//
// Parse the prototype now.
//
ParserStateRAII ResetParserState(P);
prepareForParsing("", llvm::StringRef("func.prototype.file"));
Interpreter::PushTransactionRAII pushedT(m_Interpreter);
return findFunction(foundDC, SS,
funcName, GivenArgs, objectIsConst,
Context, P, S,
overloadFunctionSelector);
}
const FunctionDecl* LookupHelper::findFunctionProto(const Decl* scopeDecl,
llvm::StringRef funcName,
llvm::StringRef funcProto,
@ -909,7 +984,7 @@ namespace cling {
llvm::SmallVector<ExprAlloc, 4> ExprMemory;
llvm::SmallVector<Expr*, 4> GivenArgs;
if (!funcProto.empty()) {
if (!ParseProto(ExprMemory,GivenArgs,Context,P,S) ) {
if (!ParseProto(ExprMemory, GivenArgs,Context,P,S) ) {
return 0;
}
}
@ -955,7 +1030,7 @@ namespace cling {
llvm::SmallVector<ExprAlloc, 4> ExprMemory;
llvm::SmallVector<Expr*, 4> GivenArgs;
if (!funcProto.empty()) {
if (!ParseProto(ExprMemory, GivenArgs,Context,P,S) ) {
if (!ParseProto(ExprMemory,GivenArgs,Context,P,S) ) {
return 0;
}
}
@ -967,6 +1042,52 @@ namespace cling {
matchFunctionSelector);
}
const FunctionDecl* LookupHelper::matchFunctionProto(const Decl* scopeDecl,
llvm::StringRef funcName,
const llvm::SmallVector<QualType, 4>& funcProto,
bool objectIsConst
) const {
assert(scopeDecl && "Decl cannot be null");
//
// Some utilities.
//
// Use P for shortness
Parser& P = *m_Parser;
Sema& S = P.getActions();
ASTContext& Context = S.getASTContext();
//
// Convert the passed decl into a nested name specifier,
// a scope spec, and a decl context.
//
// Do this 'early' to save on the expansive parser setup,
// in case of failure.
//
CXXScopeSpec SS;
DeclContext* foundDC = getContextAndSpec(SS,scopeDecl,Context,S);
if (!foundDC) return 0;
llvm::SmallVector<ExprAlloc, 4> ExprMemory;
llvm::SmallVector<Expr*, 4> GivenArgs;
if (!funcProto.empty()) {
if (!getExprProto(ExprMemory, GivenArgs, funcProto) ) {
return 0;
}
}
//
// Parse the prototype now.
//
ParserStateRAII ResetParserState(P);
prepareForParsing("", llvm::StringRef("func.prototype.file"));
Interpreter::PushTransactionRAII pushedT(m_Interpreter);
return findFunction(foundDC, SS,
funcName, GivenArgs, objectIsConst,
Context, P, S,
matchFunctionSelector);
}
static
bool ParseArgs(llvm::SmallVector<Expr*, 4> &GivenArgs,
ASTContext& Context, Parser &P, Sema &S) {

View File

@ -766,6 +766,34 @@ func_B_h_proto->print(llvm::errs());
//CHECK-NEXT: }
//
// Test finding a member function taking an int and a double argument
// in a base class using the preparse types.
//
llvm::SmallVector<clang::QualType, 4> types;
types.push_back(lookup.findType("int"));
types.push_back(lookup.findType("float"));
const clang::FunctionDecl* func_B_h_proto_type = lookup.findFunctionProto(class_A, "B_h", types);
types.pop_back();
types.push_back(lookup.findType("double"));
const clang::FunctionDecl* func_B_h_match_proto_type = lookup.matchFunctionProto(class_A, "B_h", types, false);
printf("func_B_h_proto_type: 0x%lx\n", (unsigned long) func_B_h_proto_type);
//CHECK: func_B_h_proto_type: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_h_proto_type->print(llvm::errs());
//CHECK-NEXT: void B_h(int vi, double vd) {
//CHECK-NEXT: int x = vi;
//CHECK-NEXT: double y = vd;
//CHECK-NEXT: }
printf("func_B_h_match_proto_type: 0x%lx\n", (unsigned long) func_B_h_match_proto_type);
//CHECK: func_B_h_match_proto_type: 0x{{[1-9a-f][0-9a-f]*$}}
func_B_h_match_proto_type->print(llvm::errs());
//CHECK-NEXT: void B_h(int vi, double vd) {
//CHECK-NEXT: int x = vi;
//CHECK-NEXT: double y = vd;
//CHECK-NEXT: }
//
// Test finding an overloaded member function in a base class.