//------------------------------------------------------------------------------ // CLING - the C++ LLVM-based InterpreterG :) // version: $Id$ // author: Vassil Vassilev //------------------------------------------------------------------------------ #include "cling/Utils/AST.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclarationName.h" #include "clang/Sema/Sema.h" #include "clang/Sema/Lookup.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" using namespace clang; namespace cling { namespace utils { bool Analyze::IsWrapper(const NamedDecl* ND) { if (!ND) return false; return llvm::StringRef(ND->getNameAsString()) .startswith(Synthesize::UniquePrefix); } Expr* Analyze::GetOrCreateLastExpr(FunctionDecl* FD, int* FoundAt /*=0*/, bool omitDeclStmts /*=true*/, Sema* S /*=0*/) { assert(FD && "We need a function declaration!"); assert((omitDeclStmts || S) && "Sema needs to be set when omitDeclStmts is false"); if (FoundAt) *FoundAt = -1; Expr* result = 0; if (CompoundStmt* CS = dyn_cast(FD->getBody())) { llvm::ArrayRef Stmts = llvm::makeArrayRef(CS->body_begin(), CS->size()); int indexOfLastExpr = Stmts.size(); while(indexOfLastExpr--) { if (!isa(Stmts[indexOfLastExpr])) break; } if (FoundAt) *FoundAt = indexOfLastExpr; if (indexOfLastExpr < 0) return 0; if ( (result = dyn_cast(Stmts[indexOfLastExpr])) ) return result; if (!omitDeclStmts) if (DeclStmt* DS = dyn_cast(Stmts[indexOfLastExpr])) { std::vector newBody = Stmts.vec(); for (DeclStmt::reverse_decl_iterator I = DS->decl_rbegin(), E = DS->decl_rend(); I != E; ++I) { if (VarDecl* VD = dyn_cast(*I)) { // Change the void function's return type // We can't PushDeclContext, because we don't have scope. Sema::ContextRAII pushedDC(*S, FD); QualType VDTy = VD->getType().getNonReferenceType(); // Get the location of the place we will insert. SourceLocation Loc = newBody[indexOfLastExpr]->getLocEnd().getLocWithOffset(1); Expr* DRE = S->BuildDeclRefExpr(VD, VDTy,VK_LValue, Loc).take(); assert(DRE && "Cannot be null"); indexOfLastExpr++; newBody.insert(newBody.begin() + indexOfLastExpr, DRE); // Attach the new body (note: it does dealloc/alloc of all nodes) CS->setStmts(S->getASTContext(), &newBody.front(), newBody.size()); if (FoundAt) *FoundAt = indexOfLastExpr; return DRE; } } } return result; } return result; } const char* const Synthesize::UniquePrefix = "__cling_Un1Qu3"; Expr* Synthesize::CStyleCastPtrExpr(Sema* S, QualType Ty, uint64_t Ptr) { ASTContext& Ctx = S->getASTContext(); if (!Ty->isPointerType()) Ty = Ctx.getPointerType(Ty); TypeSourceInfo* TSI = Ctx.CreateTypeSourceInfo(Ty); Expr* Result = Synthesize::IntegerLiteralExpr(Ctx, Ptr); Result = S->BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), Result).take(); assert(Result && "Cannot create CStyleCastPtrExpr"); return Result; } IntegerLiteral* Synthesize::IntegerLiteralExpr(ASTContext& C, uint64_t Ptr) { const llvm::APInt Addr(8 * sizeof(void *), Ptr); return IntegerLiteral::Create(C, Addr, C.UnsignedLongTy, SourceLocation()); } static NestedNameSpecifier* GetPartiallyDesugaredNNS(const ASTContext& Ctx, NestedNameSpecifier* scope, const llvm::SmallSet& TypesToSkip){ // Desugar the scope qualifier if needed. const Type* scope_type = scope->getAsType(); if (scope_type) { // this is not a namespace, so we might need to desugar NestedNameSpecifier* outer_scope = scope->getPrefix(); if (outer_scope) { outer_scope = GetPartiallyDesugaredNNS(Ctx, outer_scope, TypesToSkip); } QualType desugared = Transform::GetPartiallyDesugaredType(Ctx, QualType(scope_type,0), TypesToSkip, /*fullyQualify=*/false); // NOTE: Should check whether the type has changed or not. return NestedNameSpecifier::Create(Ctx,outer_scope, false /* template keyword wanted */, desugared.getTypePtr()); } return scope; } static NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx, NamespaceDecl* cl) { NamespaceDecl* outer = llvm::dyn_cast_or_null(cl->getDeclContext()); if (outer && outer->getName().size()) { NestedNameSpecifier* outerNNS = CreateNestedNameSpecifier(Ctx,outer); return NestedNameSpecifier::Create(Ctx,outerNNS, cl); } else { return NestedNameSpecifier::Create(Ctx, 0, /* no starting '::'*/ cl); } } static NestedNameSpecifier* CreateNestedNameSpecifier(const ASTContext& Ctx, TagDecl *cl) { NamedDecl* outer = llvm::dyn_cast_or_null(cl->getDeclContext()); if (outer && outer->getName().size()) { NestedNameSpecifier *outerNNS; if (cl->getDeclContext()->isNamespace()) { outerNNS = CreateNestedNameSpecifier(Ctx, llvm::dyn_cast(outer)); } else { outerNNS = CreateNestedNameSpecifier(Ctx, llvm::dyn_cast(outer)); } return NestedNameSpecifier::Create(Ctx,outerNNS, false /* template keyword wanted */, Ctx.getTypeDeclType(cl).getTypePtr()); } else { return NestedNameSpecifier::Create(Ctx, 0, /* no starting '::'*/ false /* template keyword wanted */, Ctx.getTypeDeclType(cl).getTypePtr()); } } static bool ShouldKeepTypedef(QualType QT, const llvm::SmallSet& TypesToSkip) { // Return true, if we should keep this typedef rather than desugaring it. if ( 0 != TypesToSkip.count(QT.getTypePtr()) ) return true; const TypedefType* typedeftype = llvm::dyn_cast_or_null(QT.getTypePtr()); const TypedefNameDecl* decl = typedeftype ? typedeftype->getDecl() : 0; if (decl) { const NamedDecl* outer = llvm::dyn_cast_or_null(decl->getDeclContext()); while ( outer && outer->getName().size() ) { // NOTE: Net is being cast too widely, replace by a lookup. if (outer->getName().compare("std") == 0) { return true; } outer = llvm::dyn_cast_or_null(outer->getDeclContext()); } } return false; } bool Transform::SingleStepPartiallyDesugarType(QualType& QT) { // WARNING: // // The large blocks of commented-out code in this routine // are there to support doing more desugaring in the future, // we will probably have to. // // Do not delete until we are completely sure we will // not be changing this routine again! // const Type* QTy = QT.getTypePtr(); Type::TypeClass TC = QTy->getTypeClass(); switch (TC) { // // Unconditionally sugared types. // case Type::Paren: { return false; //const ParenType* Ty = llvm::cast(QTy); //QT = Ty->desugar(); //return true; } case Type::Typedef: { const TypedefType* Ty = llvm::cast(QTy); QT = Ty->desugar(); return true; } case Type::TypeOf: { const TypeOfType* Ty = llvm::cast(QTy); QT = Ty->desugar(); return true; } case Type::Attributed: { return false; //const AttributedType* Ty = llvm::cast(QTy); //QT = Ty->desugar(); //return true; } case Type::SubstTemplateTypeParm: { return false; //const SubstTemplateTypeParmType* Ty = // llvm::cast(QTy); //QT = Ty->desugar(); //return true; } case Type::Elaborated: { return false; //const ElaboratedType* Ty = llvm::cast(QTy); ///QT = Ty->desugar(); ///return true; //return false; } // // Conditionally sugared types. // case Type::TypeOfExpr: { const TypeOfExprType* Ty = llvm::cast(QTy); if (Ty->isSugared()) { QT = Ty->desugar(); return true; } return false; } case Type::Decltype: { const DecltypeType* Ty = llvm::cast(QTy); if (Ty->isSugared()) { QT = Ty->desugar(); return true; } return false; } case Type::UnaryTransform: { return false; //const UnaryTransformType* Ty = llvm::cast(QTy); //if (Ty->isSugared()) { // QT = Ty->desugar(); // return true; //} //return false; } case Type::Auto: { return false; //const AutoType* Ty = llvm::cast(QTy); //if (Ty->isSugared()) { // QT = Ty->desugar(); // return true; //} //return false; } case Type::TemplateSpecialization: { return false; //const TemplateSpecializationType* Ty = // llvm::cast(QTy); //if (Ty->isSugared()) { // QT = Ty->desugar(); // return true; //} return false; } // Not a sugared type. default: { break; } } return false; } QualType Transform::GetPartiallyDesugaredType(const ASTContext& Ctx, QualType QT, const llvm::SmallSet& TypesToSkip, bool fullyQualify/*=true*/) { // If there are no constraints, then use the standard desugaring. if (!TypesToSkip.size() && !fullyQualify) return QT.getDesugaredType(Ctx); // In case of Int_t* we need to strip the pointer first, desugar and attach // the pointer once again. if (isa(QT.getTypePtr())) { // Get the qualifiers. Qualifiers quals = QT.getQualifiers(); QT = GetPartiallyDesugaredType(Ctx, QT->getPointeeType(), TypesToSkip, fullyQualify); QT = Ctx.getPointerType(QT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); return QT; } // In case of Int_t& we need to strip the pointer first, desugar and attach // the pointer once again. if (isa(QT.getTypePtr())) { // Get the qualifiers. bool isLValueRefTy = isa(QT.getTypePtr()); Qualifiers quals = QT.getQualifiers(); QT = GetPartiallyDesugaredType(Ctx, QT->getPointeeType(), TypesToSkip, fullyQualify); // Add the r- or l-value reference type back to the desugared one. if (isLValueRefTy) QT = Ctx.getLValueReferenceType(QT); else QT = Ctx.getRValueReferenceType(QT); // Add back the qualifiers. QT = Ctx.getQualifiedType(QT, quals); return QT; } // If the type is elaborated, first remove the prefix and then // when we are done we will as needed add back the (new) prefix. // for example for std::vector::iterator, we work on // just 'iterator' (which remember which scope its from) // and remove the typedef to get (for example), // __gnu_cxx::__normal_iterator // which is *not* in the std::vector scope and it is // the __gnu__cxx part we should use as the prefix. // NOTE: however we problably want to add the std::vector typedefs // to the list of things to skip! NestedNameSpecifier* original_prefix = 0; clang::Qualifiers prefix_qualifiers; const ElaboratedType* etype_input = llvm::dyn_cast(QT.getTypePtr()); if (etype_input) { // Intentionally, we do not care about the other compononent of // the elaborated type (the keyword) as part of the partial // desugaring (and/or name normaliztation) is to remove it. original_prefix = etype_input->getQualifier(); if (original_prefix) { const NamespaceDecl *ns = original_prefix->getAsNamespace(); if (!(ns && ns->isAnonymousNamespace())) { // We have to also desugar the prefix unless // it does not have a name (anonymous namespaces). fullyQualify = true; prefix_qualifiers = QT.getLocalQualifiers(); QT = QualType(etype_input->getNamedType().getTypePtr(),0); } else { original_prefix = 0; } } } // Desugar QT until we cannot desugar any more, or // we hit one of the special typedefs. while (1) { if (llvm::isa(QT.getTypePtr()) && ShouldKeepTypedef(QT, TypesToSkip)) { if (!fullyQualify) { return QT; } // We might have stripped the namespace/scope part, // so we must go on to add it back. break; } bool wasDesugared = SingleStepPartiallyDesugarType(QT); if (!wasDesugared) { // No more work to do, stop now. break; } } // If we have a reference or pointer we still need to // desugar what they point to. if (isa(QT.getTypePtr()) || isa(QT.getTypePtr()) ) { return GetPartiallyDesugaredType(Ctx, QT, TypesToSkip, fullyQualify); } NestedNameSpecifier* prefix = 0; const ElaboratedType* etype = llvm::dyn_cast(QT.getTypePtr()); if (etype) { // We have to also desugar the prefix. prefix = etype->getQualifier(); if (original_prefix) { // We had a scope prefix as input, let see if it is still // the same as the scope of the result and if it is, then // we use it. const clang::Type *newtype = prefix->getAsType(); if (newtype) { // Deal with a class const clang::Type *oldtype = original_prefix->getAsType(); if (oldtype && // NOTE: Should we compare the RecordDecl instead? oldtype->getAsCXXRecordDecl() == newtype->getAsCXXRecordDecl()) { // This is the same type, use the original prefix as a starting // point. prefix = GetPartiallyDesugaredNNS(Ctx,original_prefix,TypesToSkip); } else { prefix = GetPartiallyDesugaredNNS(Ctx,prefix,TypesToSkip); } } else { // Deal with namespace. This is mostly about dealing with // namespace aliases (i.e. keeping the one the user used). const NamespaceDecl *new_ns = prefix->getAsNamespace(); if (new_ns) { new_ns = new_ns->getCanonicalDecl(); } else if (NamespaceAliasDecl *alias = prefix->getAsNamespaceAlias()) { new_ns = alias->getNamespace()->getCanonicalDecl(); } if (new_ns) { const NamespaceDecl *old_ns = original_prefix->getAsNamespace(); if (old_ns) { old_ns = old_ns->getCanonicalDecl(); } else if (NamespaceAliasDecl *alias = original_prefix->getAsNamespaceAlias()) { old_ns = alias->getNamespace()->getCanonicalDecl(); } if (old_ns == new_ns) { // This is the same namespace, use the original prefix // as a starting point. prefix = original_prefix; } } } } prefix_qualifiers.addQualifiers(QT.getLocalQualifiers()); QT = QualType(etype->getNamedType().getTypePtr(),0); } else if (fullyQualify) { // Let's check whether this type should have been an elaborated type. // in which case we want to add it ... but we can't really preserve // the typedef in this case ... Decl *decl = 0; const TypedefType* typedeftype = llvm::dyn_cast_or_null(QT.getTypePtr()); if (typedeftype) { decl = typedeftype->getDecl(); } else { // There are probably other cases ... const TagType* tagdecltype = llvm::dyn_cast_or_null(QT.getTypePtr()); if (tagdecltype) { decl = tagdecltype->getDecl(); } else { decl = QT->getAsCXXRecordDecl(); } } if (decl) { NamedDecl* outer = llvm::dyn_cast_or_null(decl->getDeclContext()); NamespaceDecl* outer_ns = llvm::dyn_cast_or_null(decl->getDeclContext()); if (outer && !(outer_ns && outer_ns->isAnonymousNamespace()) && outer->getName().size() ) { if (original_prefix) { const clang::Type *oldtype = original_prefix->getAsType(); if (oldtype) { if (oldtype->getAsCXXRecordDecl() == outer) { // Same type, use the original spelling prefix = GetPartiallyDesugaredNNS(Ctx,original_prefix,TypesToSkip); outer = 0; // Cancel the later creation. } } else { const NamespaceDecl *old_ns = original_prefix->getAsNamespace(); if (old_ns) { old_ns = old_ns->getCanonicalDecl(); } else if (NamespaceAliasDecl *alias = original_prefix->getAsNamespaceAlias()) { old_ns = alias->getNamespace()->getCanonicalDecl(); } const NamespaceDecl *new_ns = llvm::dyn_cast(outer); if (new_ns) new_ns = new_ns->getCanonicalDecl(); if (old_ns == new_ns) { // This is the same namespace, use the original prefix // as a starting point. prefix = original_prefix; outer = 0; // Cancel the later creation. } } } else { // if (!original_prefix) // move the qualifiers on the outer type (avoid 'std::const string'!) prefix_qualifiers = QT.getLocalQualifiers(); QT = QualType(QT.getTypePtr(),0); } if (outer) { if (decl->getDeclContext()->isNamespace()) { prefix = CreateNestedNameSpecifier(Ctx, llvm::dyn_cast(outer)); } else { // We should only create the nested name specifier // if the outer scope is really a TagDecl. // It could also be a CXXMethod for example. TagDecl *tdecl = llvm::dyn_cast(outer); if (tdecl) { prefix = CreateNestedNameSpecifier(Ctx,tdecl); } } } } } } // In case of template specializations iterate over the arguments and // desugar them as well. if(const TemplateSpecializationType* TST = dyn_cast(QT.getTypePtr())) { bool mightHaveChanged = false; llvm::SmallVector desArgs; for(TemplateSpecializationType::iterator I = TST->begin(), E = TST->end(); I != E; ++I) { if (I->getKind() != TemplateArgument::Type) { desArgs.push_back(*I); continue; } QualType SubTy = I->getAsType(); // Check if the type needs more desugaring and recurse. if (isa(SubTy) || isa(SubTy) || isa(SubTy) || fullyQualify) { mightHaveChanged = true; desArgs.push_back(TemplateArgument(GetPartiallyDesugaredType(Ctx, SubTy, TypesToSkip, fullyQualify))); } else desArgs.push_back(*I); } // If desugaring happened allocate new type in the AST. if (mightHaveChanged) { Qualifiers qualifiers = QT.getLocalQualifiers(); QT = Ctx.getTemplateSpecializationType(TST->getTemplateName(), desArgs.data(), desArgs.size(), TST->getCanonicalTypeInternal()); QT = Ctx.getQualifiedType(QT, qualifiers); } } if (prefix) { // We intentionally always use ETK_None, we never want // the keyword (humm ... what about anonymous types?) QT = Ctx.getElaboratedType(ETK_None,prefix,QT); QT = Ctx.getQualifiedType(QT, prefix_qualifiers); } return QT; } NamespaceDecl* Lookup::Namespace(Sema* S, const char* Name, const DeclContext* Within) { DeclarationName DName = &S->Context.Idents.get(Name); LookupResult R(*S, DName, SourceLocation(), Sema::LookupNestedNameSpecifierName); if (!Within) S->LookupName(R, S->TUScope); else S->LookupQualifiedName(R, const_cast(Within)); if (R.empty()) return 0; R.resolveKind(); return dyn_cast(R.getFoundDecl()); } NamedDecl* Lookup::Named(Sema* S, const char* Name, const DeclContext* Within) { DeclarationName DName = &S->Context.Idents.get(Name); return Lookup::Named(S, DName, Within); } NamedDecl* Lookup::Named(Sema* S, const DeclarationName& Name, const DeclContext* Within) { LookupResult R(*S, Name, SourceLocation(), Sema::LookupOrdinaryName, Sema::ForRedeclaration); if (!Within) S->LookupName(R, S->TUScope); else S->LookupQualifiedName(R, const_cast(Within)); if (R.empty()) return 0; R.resolveKind(); return R.getFoundDecl(); } } // end namespace utils } // end namespace cling