/// HandleTagDeclDefinition - This callback is invoked each time a TagDecl /// to (e.g. struct, union, enum, class) is completed. This allows the /// client hack on the type, which can occur at any point in the file /// (because these can be defined in declspecs). void HandleTagDeclDefinition(TagDecl *D) override { if (Diags.hasErrorOccurred()) return; Builder->UpdateCompletedType(D); // For MSVC compatibility, treat declarations of static data members with // inline initializers as definitions. if (Ctx->getLangOpts().MSVCCompat) { for (Decl *Member : D->decls()) { if (VarDecl *VD = dyn_cast<VarDecl>(Member)) { if (Ctx->isMSStaticDataMemberInlineDefinition(VD) && Ctx->DeclMustBeEmitted(VD)) { Builder->EmitGlobal(VD); } } } } }
static void printSourceRange(CharSourceRange range, ASTContext &Ctx, raw_ostream &OS) { SourceManager &SM = Ctx.getSourceManager(); const LangOptions &langOpts = Ctx.getLangOpts(); PresumedLoc PL = SM.getPresumedLoc(range.getBegin()); OS << llvm::sys::path::filename(PL.getFilename()); OS << " [" << PL.getLine() << ":" << PL.getColumn(); OS << " - "; SourceLocation end = range.getEnd(); PL = SM.getPresumedLoc(end); unsigned endCol = PL.getColumn() - 1; if (!range.isTokenRange()) endCol += Lexer::MeasureTokenLength(end, SM, langOpts); OS << PL.getLine() << ":" << endCol << "]"; }
void UnnecessaryValueParamCheck::handleMoveFix(const ParmVarDecl &Var, const DeclRefExpr &CopyArgument, const ASTContext &Context) { auto Diag = diag(CopyArgument.getLocStart(), "parameter %0 is passed by value and only copied once; " "consider moving it to avoid unnecessary copies") << &Var; // Do not propose fixes in macros since we cannot place them correctly. if (CopyArgument.getLocStart().isMacroID()) return; const auto &SM = Context.getSourceManager(); auto EndLoc = Lexer::getLocForEndOfToken(CopyArgument.getLocation(), 0, SM, Context.getLangOpts()); Diag << FixItHint::CreateInsertion(CopyArgument.getLocStart(), "std::move(") << FixItHint::CreateInsertion(EndLoc, ")"); if (auto IncludeFixit = Inserter->CreateIncludeInsertion( SM.getFileID(CopyArgument.getLocStart()), "utility", /*IsAngled=*/true)) Diag << *IncludeFixit; }
static Cl::Kinds ClassifyConditional(ASTContext &Ctx, const Expr *True, const Expr *False) { assert(Ctx.getLangOpts().CPlusPlus && "This is only relevant for C++."); // C++ [expr.cond]p2 // If either the second or the third operand has type (cv) void, [...] // the result [...] is a prvalue. if (True->getType()->isVoidType() || False->getType()->isVoidType()) return Cl::CL_PRValue; // Note that at this point, we have already performed all conversions // according to [expr.cond]p3. // C++ [expr.cond]p4: If the second and third operands are glvalues of the // same value category [...], the result is of that [...] value category. // C++ [expr.cond]p5: Otherwise, the result is a prvalue. Cl::Kinds LCl = ClassifyInternal(Ctx, True), RCl = ClassifyInternal(Ctx, False); return LCl == RCl ? LCl : Cl::CL_PRValue; }
// Checks if 'typedef' keyword can be removed - we do it only if // it is the only declaration in a declaration chain. static bool CheckRemoval(SourceManager &SM, const SourceLocation &LocStart, const SourceLocation &LocEnd, ASTContext &Context, SourceRange &ResultRange) { FileID FID = SM.getFileID(LocEnd); llvm::MemoryBuffer *Buffer = SM.getBuffer(FID, LocEnd); Lexer DeclLexer(SM.getLocForStartOfFile(FID), Context.getLangOpts(), Buffer->getBufferStart(), SM.getCharacterData(LocStart), Buffer->getBufferEnd()); Token DeclToken; bool result = false; int parenthesisLevel = 0; while (!DeclLexer.LexFromRawLexer(DeclToken)) { if (DeclToken.getKind() == tok::TokenKind::l_paren) parenthesisLevel++; if (DeclToken.getKind() == tok::TokenKind::r_paren) parenthesisLevel--; if (DeclToken.getKind() == tok::TokenKind::semi) break; // if there is comma and we are not between open parenthesis then it is // two or more declatarions in this chain if (parenthesisLevel == 0 && DeclToken.getKind() == tok::TokenKind::comma) return false; if (DeclToken.isOneOf(tok::TokenKind::identifier, tok::TokenKind::raw_identifier)) { auto TokenStr = DeclToken.getRawIdentifier().str(); if (TokenStr == "typedef") { ResultRange = SourceRange(DeclToken.getLocation(), DeclToken.getEndLoc()); result = true; } } } // assert if there was keyword 'typedef' in declaration assert(result && "No typedef found"); return result; }
Cl Expr::ClassifyImpl(ASTContext &Ctx, SourceLocation *Loc) const { assert(!TR->isReferenceType() && "Expressions can't have reference type."); Cl::Kinds kind = ClassifyInternal(Ctx, this); // C99 6.3.2.1: An lvalue is an expression with an object type or an // incomplete type other than void. if (!Ctx.getLangOpts().CPlusPlus) { // Thus, no functions. if (TR->isFunctionType() || TR == Ctx.OverloadTy) kind = Cl::CL_Function; // No void either, but qualified void is OK because it is "other than void". // Void "lvalues" are classified as addressable void values, which are void // expressions whose address can be taken. else if (TR->isVoidType() && !TR.hasQualifiers()) kind = (kind == Cl::CL_LValue ? Cl::CL_AddressableVoid : Cl::CL_Void); } // Enable this assertion for testing. switch (kind) { case Cl::CL_LValue: assert(getValueKind() == VK_LValue); break; case Cl::CL_XValue: assert(getValueKind() == VK_XValue); break; case Cl::CL_Function: case Cl::CL_Void: case Cl::CL_AddressableVoid: case Cl::CL_DuplicateVectorComponents: case Cl::CL_MemberFunction: case Cl::CL_SubObjCPropertySetting: case Cl::CL_ClassTemporary: case Cl::CL_ArrayTemporary: case Cl::CL_ObjCMessageRValue: case Cl::CL_PRValue: assert(getValueKind() == VK_RValue); break; } Cl::ModifiableType modifiable = Cl::CM_Untested; if (Loc) modifiable = IsModifiable(Ctx, this, kind, *Loc); return Classification(kind, modifiable); }
/// ClassifyDecl - Return the classification of an expression referencing the /// given declaration. static Cl::Kinds ClassifyDecl(ASTContext &Ctx, const Decl *D) { // C++ [expr.prim.general]p6: The result is an lvalue if the entity is a // function, variable, or data member and a prvalue otherwise. // In C, functions are not lvalues. // In addition, NonTypeTemplateParmDecl derives from VarDecl but isn't an // lvalue unless it's a reference type (C++ [temp.param]p6), so we need to // special-case this. if (isa<CXXMethodDecl>(D) && cast<CXXMethodDecl>(D)->isInstance()) return Cl::CL_MemberFunction; bool islvalue; if (const NonTypeTemplateParmDecl *NTTParm = dyn_cast<NonTypeTemplateParmDecl>(D)) islvalue = NTTParm->getType()->isReferenceType(); else islvalue = isa<VarDecl>(D) || isa<FieldDecl>(D) || isa<IndirectFieldDecl>(D) || (Ctx.getLangOpts().CPlusPlus && (isa<FunctionDecl>(D) || isa<FunctionTemplateDecl>(D))); return islvalue ? Cl::CL_LValue : Cl::CL_PRValue; }
void ObjCMigrateASTConsumer::HandleTranslationUnit(ASTContext &Ctx) { TranslationUnitDecl *TU = Ctx.getTranslationUnitDecl(); for (DeclContext::decl_iterator D = TU->decls_begin(), DEnd = TU->decls_end(); D != DEnd; ++D) { if (ObjCInterfaceDecl *CDecl = dyn_cast<ObjCInterfaceDecl>(*D)) migrateObjCInterfaceDecl(Ctx, CDecl); } Rewriter rewriter(Ctx.getSourceManager(), Ctx.getLangOpts()); RewritesReceiver Rec(rewriter); Editor->applyRewrites(Rec); for (Rewriter::buffer_iterator I = rewriter.buffer_begin(), E = rewriter.buffer_end(); I != E; ++I) { FileID FID = I->first; RewriteBuffer &buf = I->second; const FileEntry *file = Ctx.getSourceManager().getFileEntryForID(FID); assert(file); SmallString<512> newText; llvm::raw_svector_ostream vecOS(newText); buf.write(vecOS); vecOS.flush(); llvm::MemoryBuffer *memBuf = llvm::MemoryBuffer::getMemBufferCopy( StringRef(newText.data(), newText.size()), file->getName()); SmallString<64> filePath(file->getName()); FileMgr.FixupRelativePath(filePath); Remapper.remap(filePath.str(), memBuf); } if (IsOutputFile) { Remapper.flushToFile(MigrateDir, Ctx.getDiagnostics()); } else { Remapper.flushToDisk(MigrateDir, Ctx.getDiagnostics()); } }
/// AnalyzeAsmString - Analyze the asm string of the current asm, decomposing /// it into pieces. If the asm string is erroneous, emit errors and return /// true, otherwise return false. unsigned GCCAsmStmt::AnalyzeAsmString(SmallVectorImpl<AsmStringPiece>&Pieces, const ASTContext &C, unsigned &DiagOffs) const { StringRef Str = getAsmString()->getString(); const char *StrStart = Str.begin(); const char *StrEnd = Str.end(); const char *CurPtr = StrStart; // "Simple" inline asms have no constraints or operands, just convert the asm // string to escape $'s. if (isSimple()) { std::string Result; for (; CurPtr != StrEnd; ++CurPtr) { switch (*CurPtr) { case '$': Result += "$$"; break; default: Result += *CurPtr; break; } } Pieces.push_back(AsmStringPiece(Result)); return 0; } // CurStringPiece - The current string that we are building up as we scan the // asm string. std::string CurStringPiece; bool HasVariants = !C.getTargetInfo().hasNoAsmVariants(); while (1) { // Done with the string? if (CurPtr == StrEnd) { if (!CurStringPiece.empty()) Pieces.push_back(AsmStringPiece(CurStringPiece)); return 0; } char CurChar = *CurPtr++; switch (CurChar) { case '$': CurStringPiece += "$$"; continue; case '{': CurStringPiece += (HasVariants ? "$(" : "{"); continue; case '|': CurStringPiece += (HasVariants ? "$|" : "|"); continue; case '}': CurStringPiece += (HasVariants ? "$)" : "}"); continue; case '%': break; default: CurStringPiece += CurChar; continue; } // Escaped "%" character in asm string. if (CurPtr == StrEnd) { // % at end of string is invalid (no escape). DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } char EscapedChar = *CurPtr++; if (EscapedChar == '%') { // %% -> % // Escaped percentage sign. CurStringPiece += '%'; continue; } if (EscapedChar == '=') { // %= -> Generate an unique ID. CurStringPiece += "${:uid}"; continue; } // Otherwise, we have an operand. If we have accumulated a string so far, // add it to the Pieces list. if (!CurStringPiece.empty()) { Pieces.push_back(AsmStringPiece(CurStringPiece)); CurStringPiece.clear(); } // Handle operands that have asmSymbolicName (e.g., %x[foo]) and those that // don't (e.g., %x4). 'x' following the '%' is the constraint modifier. const char *Begin = CurPtr - 1; // Points to the character following '%'. const char *Percent = Begin - 1; // Points to '%'. if (isLetter(EscapedChar)) { if (CurPtr == StrEnd) { // Premature end. DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } EscapedChar = *CurPtr++; } const TargetInfo &TI = C.getTargetInfo(); const SourceManager &SM = C.getSourceManager(); const LangOptions &LO = C.getLangOpts(); // Handle operands that don't have asmSymbolicName (e.g., %x4). if (isDigit(EscapedChar)) { // %n - Assembler operand n unsigned N = 0; --CurPtr; while (CurPtr != StrEnd && isDigit(*CurPtr)) N = N*10 + ((*CurPtr++)-'0'); unsigned NumOperands = getNumOutputs() + getNumPlusOperands() + getNumInputs(); if (N >= NumOperands) { DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_operand_number; } // Str contains "x4" (Operand without the leading %). std::string Str(Begin, CurPtr - Begin); // (BeginLoc, EndLoc) represents the range of the operand we are currently // processing. Unlike Str, the range includes the leading '%'. SourceLocation BeginLoc = getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI); SourceLocation EndLoc = getAsmString()->getLocationOfByte(CurPtr - StrStart, SM, LO, TI); Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc); continue; } // Handle operands that have asmSymbolicName (e.g., %x[foo]). if (EscapedChar == '[') { DiagOffs = CurPtr-StrStart-1; // Find the ']'. const char *NameEnd = (const char*)memchr(CurPtr, ']', StrEnd-CurPtr); if (NameEnd == nullptr) return diag::err_asm_unterminated_symbolic_operand_name; if (NameEnd == CurPtr) return diag::err_asm_empty_symbolic_operand_name; StringRef SymbolicName(CurPtr, NameEnd - CurPtr); int N = getNamedOperand(SymbolicName); if (N == -1) { // Verify that an operand with that name exists. DiagOffs = CurPtr-StrStart; return diag::err_asm_unknown_symbolic_operand_name; } // Str contains "x[foo]" (Operand without the leading %). std::string Str(Begin, NameEnd + 1 - Begin); // (BeginLoc, EndLoc) represents the range of the operand we are currently // processing. Unlike Str, the range includes the leading '%'. SourceLocation BeginLoc = getAsmString()->getLocationOfByte(Percent - StrStart, SM, LO, TI); SourceLocation EndLoc = getAsmString()->getLocationOfByte(NameEnd + 1 - StrStart, SM, LO, TI); Pieces.emplace_back(N, std::move(Str), BeginLoc, EndLoc); CurPtr = NameEnd+1; continue; } DiagOffs = CurPtr-StrStart-1; return diag::err_asm_invalid_escape; } }
explicit InserterVisitor(CompilerInstance *CI) : astContext(&(CI->getASTContext())) { rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts()); }
/// GetDiagForGotoScopeDecl - If this decl induces a new goto scope, return a /// diagnostic that should be emitted if control goes over it. If not, return 0. static ScopePair GetDiagForGotoScopeDecl(ASTContext &Context, const Decl *D) { if (const VarDecl *VD = dyn_cast<VarDecl>(D)) { unsigned InDiag = 0; if (VD->getType()->isVariablyModifiedType()) InDiag = diag::note_protected_by_vla; if (VD->hasAttr<BlocksAttr>()) return ScopePair(diag::note_protected_by___block, diag::note_exits___block); if (VD->hasAttr<CleanupAttr>()) return ScopePair(diag::note_protected_by_cleanup, diag::note_exits_cleanup); if (Context.getLangOpts().ObjCAutoRefCount && VD->hasLocalStorage()) { switch (VD->getType().getObjCLifetime()) { case Qualifiers::OCL_None: case Qualifiers::OCL_ExplicitNone: case Qualifiers::OCL_Autoreleasing: break; case Qualifiers::OCL_Strong: case Qualifiers::OCL_Weak: return ScopePair(diag::note_protected_by_objc_ownership, diag::note_exits_objc_ownership); } } if (Context.getLangOpts().CPlusPlus && VD->hasLocalStorage()) { // C++11 [stmt.dcl]p3: // A program that jumps from a point where a variable with automatic // storage duration is not in scope to a point where it is in scope // is ill-formed unless the variable has scalar type, class type with // a trivial default constructor and a trivial destructor, a // cv-qualified version of one of these types, or an array of one of // the preceding types and is declared without an initializer. // C++03 [stmt.dcl.p3: // A program that jumps from a point where a local variable // with automatic storage duration is not in scope to a point // where it is in scope is ill-formed unless the variable has // POD type and is declared without an initializer. const Expr *Init = VD->getInit(); if (!Init) return ScopePair(InDiag, 0); const ExprWithCleanups *EWC = dyn_cast<ExprWithCleanups>(Init); if (EWC) Init = EWC->getSubExpr(); const MaterializeTemporaryExpr *M = NULL; Init = Init->findMaterializedTemporary(M); SmallVector<SubobjectAdjustment, 2> Adjustments; Init = Init->skipRValueSubobjectAdjustments(Adjustments); QualType QT = Init->getType(); if (QT.isNull()) return ScopePair(diag::note_protected_by_variable_init, 0); const Type *T = QT.getTypePtr(); if (T->isArrayType()) T = T->getBaseElementTypeUnsafe(); const CXXRecordDecl *Record = T->getAsCXXRecordDecl(); if (!Record) return ScopePair(diag::note_protected_by_variable_init, 0); // If we need to call a non trivial destructor for this variable, // record an out diagnostic. unsigned OutDiag = 0; if (!Init->isGLValue() && !Record->hasTrivialDestructor()) OutDiag = diag::note_exits_dtor; if (const CXXConstructExpr *cce = dyn_cast<CXXConstructExpr>(Init)) { const CXXConstructorDecl *ctor = cce->getConstructor(); if (ctor->isTrivial() && ctor->isDefaultConstructor()) { if (OutDiag) InDiag = diag::note_protected_by_variable_nontriv_destructor; else if (!Record->isPOD()) InDiag = diag::note_protected_by_variable_non_pod; return ScopePair(InDiag, OutDiag); } } return ScopePair(diag::note_protected_by_variable_init, OutDiag); } return ScopePair(InDiag, 0); } if (const TypedefDecl *TD = dyn_cast<TypedefDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) return ScopePair(diag::note_protected_by_vla_typedef, 0); } if (const TypeAliasDecl *TD = dyn_cast<TypeAliasDecl>(D)) { if (TD->getUnderlyingType()->isVariablyModifiedType()) return ScopePair(diag::note_protected_by_vla_type_alias, 0); } return ScopePair(0U, 0U); }
static bool checkReturnValueType(const ASTContext &Ctx, const Expr *E, QualType &DeducedType, QualType &AlternateType) { // Handle ReturnStmts with no expressions. if (!E) { if (AlternateType.isNull()) AlternateType = Ctx.VoidTy; return Ctx.hasSameType(DeducedType, Ctx.VoidTy); } QualType StrictType = E->getType(); QualType LooseType = StrictType; // In C, enum constants have the type of their underlying integer type, // not the enum. When inferring block return types, we should allow // the enum type if an enum constant is used, unless the enum is // anonymous (in which case there can be no variables of its type). if (!Ctx.getLangOpts().CPlusPlus) { const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(E->IgnoreParenImpCasts()); if (DRE) { const Decl *D = DRE->getDecl(); if (const EnumConstantDecl *ECD = dyn_cast<EnumConstantDecl>(D)) { const EnumDecl *Enum = cast<EnumDecl>(ECD->getDeclContext()); if (Enum->getDeclName() || Enum->getTypedefNameForAnonDecl()) LooseType = Ctx.getTypeDeclType(Enum); } } } // Special case for the first return statement we find. // The return type has already been tentatively set, but we might still // have an alternate type we should prefer. if (AlternateType.isNull()) AlternateType = LooseType; if (Ctx.hasSameType(DeducedType, StrictType)) { // FIXME: The loose type is different when there are constants from two // different enums. We could consider warning here. if (AlternateType != Ctx.DependentTy) if (!Ctx.hasSameType(AlternateType, LooseType)) AlternateType = Ctx.VoidTy; return true; } if (Ctx.hasSameType(DeducedType, LooseType)) { // Use DependentTy to signal that we're using an alternate type and may // need to add casts somewhere. AlternateType = Ctx.DependentTy; return true; } if (Ctx.hasSameType(AlternateType, StrictType) || Ctx.hasSameType(AlternateType, LooseType)) { DeducedType = AlternateType; // Use DependentTy to signal that we're using an alternate type and may // need to add casts somewhere. AlternateType = Ctx.DependentTy; return true; } return false; }
void HTMLPrinter::Initialize(ASTContext &context) { R.setSourceMgr(context.getSourceManager(), context.getLangOpts()); }
explicit ExampleVisitor(CompilerInstance *CI) : astContext(&(CI->getASTContext())) // initialize private members { rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts()); }
static Cl::Kinds ClassifyInternal(ASTContext &Ctx, const Expr *E) { // This function takes the first stab at classifying expressions. const LangOptions &Lang = Ctx.getLangOpts(); switch (E->getStmtClass()) { case Stmt::NoStmtClass: #define ABSTRACT_STMT(Kind) #define STMT(Kind, Base) case Expr::Kind##Class: #define EXPR(Kind, Base) #include "clang/AST/StmtNodes.inc" llvm_unreachable("cannot classify a statement"); // First come the expressions that are always lvalues, unconditionally. case Expr::ObjCIsaExprClass: // C++ [expr.prim.general]p1: A string literal is an lvalue. case Expr::StringLiteralClass: // @encode is equivalent to its string case Expr::ObjCEncodeExprClass: // __func__ and friends are too. case Expr::PredefinedExprClass: // Property references are lvalues case Expr::ObjCSubscriptRefExprClass: case Expr::ObjCPropertyRefExprClass: // C++ [expr.typeid]p1: The result of a typeid expression is an lvalue of... case Expr::CXXTypeidExprClass: // Unresolved lookups and uncorrected typos get classified as lvalues. // FIXME: Is this wise? Should they get their own kind? case Expr::UnresolvedLookupExprClass: case Expr::UnresolvedMemberExprClass: case Expr::TypoExprClass: case Expr::DependentCoawaitExprClass: case Expr::CXXDependentScopeMemberExprClass: case Expr::DependentScopeDeclRefExprClass: // ObjC instance variables are lvalues // FIXME: ObjC++0x might have different rules case Expr::ObjCIvarRefExprClass: case Expr::FunctionParmPackExprClass: case Expr::MSPropertyRefExprClass: case Expr::MSPropertySubscriptExprClass: case Expr::OMPArraySectionExprClass: return Cl::CL_LValue; // C99 6.5.2.5p5 says that compound literals are lvalues. // In C++, they're prvalue temporaries, except for file-scope arrays. case Expr::CompoundLiteralExprClass: return !E->isLValue() ? ClassifyTemporary(E->getType()) : Cl::CL_LValue; // Expressions that are prvalues. case Expr::CXXBoolLiteralExprClass: case Expr::CXXPseudoDestructorExprClass: case Expr::UnaryExprOrTypeTraitExprClass: case Expr::CXXNewExprClass: case Expr::CXXThisExprClass: case Expr::CXXNullPtrLiteralExprClass: case Expr::ImaginaryLiteralClass: case Expr::GNUNullExprClass: case Expr::OffsetOfExprClass: case Expr::CXXThrowExprClass: case Expr::ShuffleVectorExprClass: case Expr::ConvertVectorExprClass: case Expr::IntegerLiteralClass: case Expr::CharacterLiteralClass: case Expr::AddrLabelExprClass: case Expr::CXXDeleteExprClass: case Expr::ImplicitValueInitExprClass: case Expr::BlockExprClass: case Expr::FloatingLiteralClass: case Expr::CXXNoexceptExprClass: case Expr::CXXScalarValueInitExprClass: case Expr::TypeTraitExprClass: case Expr::ArrayTypeTraitExprClass: case Expr::ExpressionTraitExprClass: case Expr::ObjCSelectorExprClass: case Expr::ObjCProtocolExprClass: case Expr::ObjCStringLiteralClass: case Expr::ObjCBoxedExprClass: case Expr::ObjCArrayLiteralClass: case Expr::ObjCDictionaryLiteralClass: case Expr::ObjCBoolLiteralExprClass: case Expr::ObjCAvailabilityCheckExprClass: case Expr::ParenListExprClass: case Expr::SizeOfPackExprClass: case Expr::SubstNonTypeTemplateParmPackExprClass: case Expr::AsTypeExprClass: case Expr::ObjCIndirectCopyRestoreExprClass: case Expr::AtomicExprClass: case Expr::CXXFoldExprClass: case Expr::ArrayInitLoopExprClass: case Expr::ArrayInitIndexExprClass: case Expr::NoInitExprClass: case Expr::DesignatedInitUpdateExprClass: case Expr::CoyieldExprClass: return Cl::CL_PRValue; // Next come the complicated cases. case Expr::SubstNonTypeTemplateParmExprClass: return ClassifyInternal(Ctx, cast<SubstNonTypeTemplateParmExpr>(E)->getReplacement()); // C, C++98 [expr.sub]p1: The result is an lvalue of type "T". // C++11 (DR1213): in the case of an array operand, the result is an lvalue // if that operand is an lvalue and an xvalue otherwise. // Subscripting vector types is more like member access. case Expr::ArraySubscriptExprClass: if (cast<ArraySubscriptExpr>(E)->getBase()->getType()->isVectorType()) return ClassifyInternal(Ctx, cast<ArraySubscriptExpr>(E)->getBase()); if (Lang.CPlusPlus11) { // Step over the array-to-pointer decay if present, but not over the // temporary materialization. auto *Base = cast<ArraySubscriptExpr>(E)->getBase()->IgnoreImpCasts(); if (Base->getType()->isArrayType()) return ClassifyInternal(Ctx, Base); } return Cl::CL_LValue; // C++ [expr.prim.general]p3: The result is an lvalue if the entity is a // function or variable and a prvalue otherwise. case Expr::DeclRefExprClass: if (E->getType() == Ctx.UnknownAnyTy) return isa<FunctionDecl>(cast<DeclRefExpr>(E)->getDecl()) ? Cl::CL_PRValue : Cl::CL_LValue; return ClassifyDecl(Ctx, cast<DeclRefExpr>(E)->getDecl()); // Member access is complex. case Expr::MemberExprClass: return ClassifyMemberExpr(Ctx, cast<MemberExpr>(E)); case Expr::UnaryOperatorClass: switch (cast<UnaryOperator>(E)->getOpcode()) { // C++ [expr.unary.op]p1: The unary * operator performs indirection: // [...] the result is an lvalue referring to the object or function // to which the expression points. case UO_Deref: return Cl::CL_LValue; // GNU extensions, simply look through them. case UO_Extension: return ClassifyInternal(Ctx, cast<UnaryOperator>(E)->getSubExpr()); // Treat _Real and _Imag basically as if they were member // expressions: l-value only if the operand is a true l-value. case UO_Real: case UO_Imag: { const Expr *Op = cast<UnaryOperator>(E)->getSubExpr()->IgnoreParens(); Cl::Kinds K = ClassifyInternal(Ctx, Op); if (K != Cl::CL_LValue) return K; if (isa<ObjCPropertyRefExpr>(Op)) return Cl::CL_SubObjCPropertySetting; return Cl::CL_LValue; } // C++ [expr.pre.incr]p1: The result is the updated operand; it is an // lvalue, [...] // Not so in C. case UO_PreInc: case UO_PreDec: return Lang.CPlusPlus ? Cl::CL_LValue : Cl::CL_PRValue; default: return Cl::CL_PRValue; } case Expr::OpaqueValueExprClass: return ClassifyExprValueKind(Lang, E, E->getValueKind()); // Pseudo-object expressions can produce l-values with reference magic. case Expr::PseudoObjectExprClass: return ClassifyExprValueKind(Lang, E, cast<PseudoObjectExpr>(E)->getValueKind()); // Implicit casts are lvalues if they're lvalue casts. Other than that, we // only specifically record class temporaries. case Expr::ImplicitCastExprClass: return ClassifyExprValueKind(Lang, E, E->getValueKind()); // C++ [expr.prim.general]p4: The presence of parentheses does not affect // whether the expression is an lvalue. case Expr::ParenExprClass: return ClassifyInternal(Ctx, cast<ParenExpr>(E)->getSubExpr()); // C11 6.5.1.1p4: [A generic selection] is an lvalue, a function designator, // or a void expression if its result expression is, respectively, an // lvalue, a function designator, or a void expression. case Expr::GenericSelectionExprClass: if (cast<GenericSelectionExpr>(E)->isResultDependent()) return Cl::CL_PRValue; return ClassifyInternal(Ctx,cast<GenericSelectionExpr>(E)->getResultExpr()); case Expr::BinaryOperatorClass: case Expr::CompoundAssignOperatorClass: // C doesn't have any binary expressions that are lvalues. if (Lang.CPlusPlus) return ClassifyBinaryOp(Ctx, cast<BinaryOperator>(E)); return Cl::CL_PRValue; case Expr::CallExprClass: case Expr::CXXOperatorCallExprClass: case Expr::CXXMemberCallExprClass: case Expr::UserDefinedLiteralClass: case Expr::CUDAKernelCallExprClass: return ClassifyUnnamed(Ctx, cast<CallExpr>(E)->getCallReturnType(Ctx)); // __builtin_choose_expr is equivalent to the chosen expression. case Expr::ChooseExprClass: return ClassifyInternal(Ctx, cast<ChooseExpr>(E)->getChosenSubExpr()); // Extended vector element access is an lvalue unless there are duplicates // in the shuffle expression. case Expr::ExtVectorElementExprClass: if (cast<ExtVectorElementExpr>(E)->containsDuplicateElements()) return Cl::CL_DuplicateVectorComponents; if (cast<ExtVectorElementExpr>(E)->isArrow()) return Cl::CL_LValue; return ClassifyInternal(Ctx, cast<ExtVectorElementExpr>(E)->getBase()); // Simply look at the actual default argument. case Expr::CXXDefaultArgExprClass: return ClassifyInternal(Ctx, cast<CXXDefaultArgExpr>(E)->getExpr()); // Same idea for default initializers. case Expr::CXXDefaultInitExprClass: return ClassifyInternal(Ctx, cast<CXXDefaultInitExpr>(E)->getExpr()); // Same idea for temporary binding. case Expr::CXXBindTemporaryExprClass: return ClassifyInternal(Ctx, cast<CXXBindTemporaryExpr>(E)->getSubExpr()); // And the cleanups guard. case Expr::ExprWithCleanupsClass: return ClassifyInternal(Ctx, cast<ExprWithCleanups>(E)->getSubExpr()); // Casts depend completely on the target type. All casts work the same. case Expr::CStyleCastExprClass: case Expr::CXXFunctionalCastExprClass: case Expr::CXXStaticCastExprClass: case Expr::CXXDynamicCastExprClass: case Expr::CXXReinterpretCastExprClass: case Expr::CXXConstCastExprClass: case Expr::ObjCBridgedCastExprClass: // Only in C++ can casts be interesting at all. if (!Lang.CPlusPlus) return Cl::CL_PRValue; return ClassifyUnnamed(Ctx, cast<ExplicitCastExpr>(E)->getTypeAsWritten()); case Expr::CXXUnresolvedConstructExprClass: return ClassifyUnnamed(Ctx, cast<CXXUnresolvedConstructExpr>(E)->getTypeAsWritten()); case Expr::BinaryConditionalOperatorClass: { if (!Lang.CPlusPlus) return Cl::CL_PRValue; const BinaryConditionalOperator *co = cast<BinaryConditionalOperator>(E); return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); } case Expr::ConditionalOperatorClass: { // Once again, only C++ is interesting. if (!Lang.CPlusPlus) return Cl::CL_PRValue; const ConditionalOperator *co = cast<ConditionalOperator>(E); return ClassifyConditional(Ctx, co->getTrueExpr(), co->getFalseExpr()); } // ObjC message sends are effectively function calls, if the target function // is known. case Expr::ObjCMessageExprClass: if (const ObjCMethodDecl *Method = cast<ObjCMessageExpr>(E)->getMethodDecl()) { Cl::Kinds kind = ClassifyUnnamed(Ctx, Method->getReturnType()); return (kind == Cl::CL_PRValue) ? Cl::CL_ObjCMessageRValue : kind; } return Cl::CL_PRValue; // Some C++ expressions are always class temporaries. case Expr::CXXConstructExprClass: case Expr::CXXInheritedCtorInitExprClass: case Expr::CXXTemporaryObjectExprClass: case Expr::LambdaExprClass: case Expr::CXXStdInitializerListExprClass: return Cl::CL_ClassTemporary; case Expr::VAArgExprClass: return ClassifyUnnamed(Ctx, E->getType()); case Expr::DesignatedInitExprClass: return ClassifyInternal(Ctx, cast<DesignatedInitExpr>(E)->getInit()); case Expr::StmtExprClass: { const CompoundStmt *S = cast<StmtExpr>(E)->getSubStmt(); if (const Expr *LastExpr = dyn_cast_or_null<Expr>(S->body_back())) return ClassifyUnnamed(Ctx, LastExpr->getType()); return Cl::CL_PRValue; } case Expr::CXXUuidofExprClass: return Cl::CL_LValue; case Expr::PackExpansionExprClass: return ClassifyInternal(Ctx, cast<PackExpansionExpr>(E)->getPattern()); case Expr::MaterializeTemporaryExprClass: return cast<MaterializeTemporaryExpr>(E)->isBoundToLvalueReference() ? Cl::CL_LValue : Cl::CL_XValue; case Expr::InitListExprClass: // An init list can be an lvalue if it is bound to a reference and // contains only one element. In that case, we look at that element // for an exact classification. Init list creation takes care of the // value kind for us, so we only need to fine-tune. if (E->isRValue()) return ClassifyExprValueKind(Lang, E, E->getValueKind()); assert(cast<InitListExpr>(E)->getNumInits() == 1 && "Only 1-element init lists can be glvalues."); return ClassifyInternal(Ctx, cast<InitListExpr>(E)->getInit(0)); case Expr::CoawaitExprClass: return ClassifyInternal(Ctx, cast<CoawaitExpr>(E)->getResumeExpr()); } llvm_unreachable("unhandled expression kind in classification"); }
void APValue::printPretty(raw_ostream &Out, ASTContext &Ctx, QualType Ty) const{ switch (getKind()) { case APValue::Uninitialized: Out << "<uninitialized>"; return; case APValue::Int: if (Ty->isBooleanType()) Out << (getInt().getBoolValue() ? "true" : "false"); else Out << getInt(); return; case APValue::Float: Out << GetApproxValue(getFloat()); return; case APValue::FixedPoint: Out << getFixedPoint(); return; case APValue::Vector: { Out << '{'; QualType ElemTy = Ty->getAs<VectorType>()->getElementType(); getVectorElt(0).printPretty(Out, Ctx, ElemTy); for (unsigned i = 1; i != getVectorLength(); ++i) { Out << ", "; getVectorElt(i).printPretty(Out, Ctx, ElemTy); } Out << '}'; return; } case APValue::ComplexInt: Out << getComplexIntReal() << "+" << getComplexIntImag() << "i"; return; case APValue::ComplexFloat: Out << GetApproxValue(getComplexFloatReal()) << "+" << GetApproxValue(getComplexFloatImag()) << "i"; return; case APValue::LValue: { bool IsReference = Ty->isReferenceType(); QualType InnerTy = IsReference ? Ty.getNonReferenceType() : Ty->getPointeeType(); if (InnerTy.isNull()) InnerTy = Ty; LValueBase Base = getLValueBase(); if (!Base) { if (isNullPointer()) { Out << (Ctx.getLangOpts().CPlusPlus11 ? "nullptr" : "0"); } else if (IsReference) { Out << "*(" << InnerTy.stream(Ctx.getPrintingPolicy()) << "*)" << getLValueOffset().getQuantity(); } else { Out << "(" << Ty.stream(Ctx.getPrintingPolicy()) << ")" << getLValueOffset().getQuantity(); } return; } if (!hasLValuePath()) { // No lvalue path: just print the offset. CharUnits O = getLValueOffset(); CharUnits S = Ctx.getTypeSizeInChars(InnerTy); if (!O.isZero()) { if (IsReference) Out << "*("; if (O % S) { Out << "(char*)"; S = CharUnits::One(); } Out << '&'; } else if (!IsReference) Out << '&'; if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) Out << *VD; else { assert(Base.get<const Expr *>() != nullptr && "Expecting non-null Expr"); Base.get<const Expr*>()->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); } if (!O.isZero()) { Out << " + " << (O / S); if (IsReference) Out << ')'; } return; } // We have an lvalue path. Print it out nicely. if (!IsReference) Out << '&'; else if (isLValueOnePastTheEnd()) Out << "*(&"; QualType ElemTy; if (const ValueDecl *VD = Base.dyn_cast<const ValueDecl*>()) { Out << *VD; ElemTy = VD->getType(); } else { const Expr *E = Base.get<const Expr*>(); assert(E != nullptr && "Expecting non-null Expr"); E->printPretty(Out, nullptr, Ctx.getPrintingPolicy()); ElemTy = E->getType(); } ArrayRef<LValuePathEntry> Path = getLValuePath(); const CXXRecordDecl *CastToBase = nullptr; for (unsigned I = 0, N = Path.size(); I != N; ++I) { if (ElemTy->getAs<RecordType>()) { // The lvalue refers to a class type, so the next path entry is a base // or member. const Decl *BaseOrMember = Path[I].getAsBaseOrMember().getPointer(); if (const CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(BaseOrMember)) { CastToBase = RD; ElemTy = Ctx.getRecordType(RD); } else { const ValueDecl *VD = cast<ValueDecl>(BaseOrMember); Out << "."; if (CastToBase) Out << *CastToBase << "::"; Out << *VD; ElemTy = VD->getType(); } } else { // The lvalue must refer to an array. Out << '[' << Path[I].getAsArrayIndex() << ']'; ElemTy = Ctx.getAsArrayType(ElemTy)->getElementType(); } } // Handle formatting of one-past-the-end lvalues. if (isLValueOnePastTheEnd()) { // FIXME: If CastToBase is non-0, we should prefix the output with // "(CastToBase*)". Out << " + 1"; if (IsReference) Out << ')'; } return; } case APValue::Array: { const ArrayType *AT = Ctx.getAsArrayType(Ty); QualType ElemTy = AT->getElementType(); Out << '{'; if (unsigned N = getArrayInitializedElts()) { getArrayInitializedElt(0).printPretty(Out, Ctx, ElemTy); for (unsigned I = 1; I != N; ++I) { Out << ", "; if (I == 10) { // Avoid printing out the entire contents of large arrays. Out << "..."; break; } getArrayInitializedElt(I).printPretty(Out, Ctx, ElemTy); } } Out << '}'; return; } case APValue::Struct: { Out << '{'; const RecordDecl *RD = Ty->getAs<RecordType>()->getDecl(); bool First = true; if (unsigned N = getStructNumBases()) { const CXXRecordDecl *CD = cast<CXXRecordDecl>(RD); CXXRecordDecl::base_class_const_iterator BI = CD->bases_begin(); for (unsigned I = 0; I != N; ++I, ++BI) { assert(BI != CD->bases_end()); if (!First) Out << ", "; getStructBase(I).printPretty(Out, Ctx, BI->getType()); First = false; } } for (const auto *FI : RD->fields()) { if (!First) Out << ", "; if (FI->isUnnamedBitfield()) continue; getStructField(FI->getFieldIndex()). printPretty(Out, Ctx, FI->getType()); First = false; } Out << '}'; return; } case APValue::Union: Out << '{'; if (const FieldDecl *FD = getUnionField()) { Out << "." << *FD << " = "; getUnionValue().printPretty(Out, Ctx, FD->getType()); } Out << '}'; return; case APValue::MemberPointer: // FIXME: This is not enough to unambiguously identify the member in a // multiple-inheritance scenario. if (const ValueDecl *VD = getMemberPointerDecl()) { Out << '&' << *cast<CXXRecordDecl>(VD->getDeclContext()) << "::" << *VD; return; } Out << "0"; return; case APValue::AddrLabelDiff: Out << "&&" << getAddrLabelDiffLHS()->getLabel()->getName(); Out << " - "; Out << "&&" << getAddrLabelDiffRHS()->getLabel()->getName(); return; } llvm_unreachable("Unknown APValue kind!"); }
void SynthesizeRemovalConsumer::removeSynthesizeDirectives(DeclContext *DC) { for(auto I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { // encounters @implementatian if (auto D = dyn_cast<ObjCImplDecl>(*I)) { // iterate through all the @synthesize / @dynamic directives for (auto PI = D->propimpl_begin(), PE = D->propimpl_end(); PI != PE; ++PI) { auto P = *PI; auto SR = P->getSourceRange(); // ignore if it's already an automatic @synthesize if (SR.getBegin().isInvalid()) { continue; } // ignore @dynamic if (P->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) { continue; } // if the ivar is not declared in the place where @synthesize is // (i.e. it is backed by some real ivar declared in @interface), // don't remove it auto PID = P->getPropertyIvarDecl(); if (P->getPropertyIvarDeclLoc() != PID->getLocation()) { continue; } // get the context in which the @property resides auto PD = P->getPropertyDecl(); auto PDC = PD->getDeclContext(); auto ID = dyn_cast<ObjCInterfaceDecl>(PDC); if (!ID) { continue; } // see if it's an @interface definition; this is false for @protocol // and we can only remove the synthesize decl for properties // declared within an @interface and not in @protocol if (!ID->isThisDeclarationADefinition()) { continue; } // check if the interface has the attribute // __attribute__((objc_requires_property_definitions)); if yes, the // directive cannot be removed bool attrObjCRequiresPropertyDefs = false; for (auto AI = ID->attr_begin(), AE = ID->attr_end(); AI != AE; ++AI) { if ((*AI)->getKind() == attr::ObjCRequiresPropertyDefs) { attrObjCRequiresPropertyDefs = true; break; } } if (attrObjCRequiresPropertyDefs) { continue; } // if there is both a manual getter *and* setter, it's equivalent to // a @dynamic, so we have to skip it auto GD = D->getInstanceMethod(PD->getGetterName()); auto SD = D->getInstanceMethod(PD->getSetterName()); if (GD && SD) { continue; } // another case for read-only properties if (GD && PD->isReadOnly()) { continue; } // scan past the ; token, get the end location SourceLocation EL = Lexer::findLocationAfterToken(SR.getEnd(), tok::semi, astContext->getSourceManager(), astContext->getLangOpts(), false); // probably run into a comma (compound directive) if (EL.isInvalid()) { continue; } // if it's a sub-directive after the comma, scan from the // beginning of the @synthesize token bool isCompoundDirective = false; const char *BCD = astContext->getSourceManager() .getCharacterData(SR.getBegin()); const char *ECD = astContext->getSourceManager() .getCharacterData(EL); while (BCD != ECD) { if (*BCD == ',') { isCompoundDirective = true; break; } ++BCD; } if (isCompoundDirective) { continue; } // check if the synthesized ivar name is not the same // as the property's name plus underscore std::string PIDN = PID->getNameAsString(); std::string PDN = PD->getNameAsString(); // handle the case where it's not @synthesize x = _x; std::string underscored = std::string("_") + PDN; if (PIDN != PDN) { if (PIDN != underscored) { continue; } } // see if the property is actually an ivar name of // some parent class! auto IF = preprocessor->getIdentifierInfo(underscored); if (IF) { auto IVDL = ID->lookupInstanceVariable(IF); if (IVDL && IVDL->getContainingInterface() != ID) { continue; } } // if parent class also have a property of the same name, // but of a different type, we can't remove it bool isOverridingProperty = false; auto S = ID->getSuperClass(); while (S) { auto SP = S->FindPropertyVisibleInPrimaryClass( PD->getIdentifier()); if (SP && (SP != PD)) { isOverridingProperty = true; break; } S = S->getSuperClass(); } if (isOverridingProperty) { continue; } // do the removal: record the removed directive removeSet.insert(P); // we want to remove the entire line if it becomes empty Rewriter::RewriteOptions RO; RO.RemoveLineIfEmpty = true; // and remove the @synthesize SourceRange RSR(SR.getBegin(), EL); rewriter.RemoveText(RSR, RO); } // PI } // D // descend into the next level (namespace, etc.) if (auto innerDC = dyn_cast<DeclContext>(*I)) { removeSynthesizeDirectives(innerDC); } } // DC }
FileInstrumentation::FileInstrumentation(const InstrumentationOptions& options, utils::SourceFileRef sourceFile, FileInstrumentation* parent, const ASTContext& astContext) : m_options(options), m_sourceFile{sourceFile}, m_parent{parent}, m_astContext(astContext), m_rewriter{m_sourceFile, astContext.getLangOpts()}, m_signals{m_sourceFile, astContext.getLangOpts()} { }
StringRef getText(CharSourceRange Range, const ASTContext &Context) { return Lexer::getSourceText(Range, Context.getSourceManager(), Context.getLangOpts()); }