/// 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);
            }
          }
        }
      }
    }
Exemple #2
0
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;
}
Exemple #8
0
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());
  }
}
Exemple #9
0
/// 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;
  }
}
Exemple #10
0
 explicit InserterVisitor(CompilerInstance *CI)
   : astContext(&(CI->getASTContext()))
 {
     rewriter.setSourceMgr(astContext->getSourceManager(), astContext->getLangOpts());
 }
Exemple #11
0
/// 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);
}
Exemple #12
0
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;
}
Exemple #13
0
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");
}
Exemple #16
0
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!");
}
Exemple #17
0
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()} {
}
Exemple #19
0
StringRef getText(CharSourceRange Range, const ASTContext &Context) {
  return Lexer::getSourceText(Range, Context.getSourceManager(),
                              Context.getLangOpts());
}