void ReplaceAutoPtrCheck::check(const MatchFinder::MatchResult &Result) {
  SourceManager &SM = *Result.SourceManager;
  if (const auto *E =
          Result.Nodes.getNodeAs<Expr>(AutoPtrOwnershipTransferId)) {
    CharSourceRange Range = Lexer::makeFileCharRange(
        CharSourceRange::getTokenRange(E->getSourceRange()), SM, LangOptions());

    if (Range.isInvalid())
      return;

    auto Diag = diag(Range.getBegin(), "use std::move to transfer ownership")
                << FixItHint::CreateInsertion(Range.getBegin(), "std::move(")
                << FixItHint::CreateInsertion(Range.getEnd(), ")");

    auto Insertion =
        Inserter->CreateIncludeInsertion(SM.getMainFileID(), "utility",
                                         /*IsAngled=*/true);
    if (Insertion.hasValue())
      Diag << Insertion.getValue();

    return;
  }

  SourceLocation IdentifierLoc;
  if (const auto *TL = Result.Nodes.getNodeAs<TypeLoc>(AutoPtrTokenId)) {
    IdentifierLoc = locateFromTypeLoc(TL, SM);
  } else if (const auto *D =
                 Result.Nodes.getNodeAs<UsingDecl>(AutoPtrTokenId)) {
    IdentifierLoc = locateFromUsingDecl(D, SM);
  } else {
    llvm_unreachable("Bad Callback. No node provided.");
  }

  if (IdentifierLoc.isMacroID())
    IdentifierLoc = SM.getSpellingLoc(IdentifierLoc);

  // Ensure that only the 'auto_ptr' token is replaced and not the template
  // aliases.
  if (!checkTokenIsAutoPtr(IdentifierLoc, SM, LangOptions()))
    return;

  SourceLocation EndLoc =
      IdentifierLoc.getLocWithOffset(strlen("auto_ptr") - 1);
  diag(IdentifierLoc, "auto_ptr is deprecated, use unique_ptr instead")
      << FixItHint::CreateReplacement(SourceRange(IdentifierLoc, EndLoc),
                                      "unique_ptr");
}
void WhitespaceManager::replaceWhitespaceInToken(
    const FormatToken &Tok, unsigned Offset, unsigned ReplaceChars,
    StringRef PreviousPostfix, StringRef CurrentPrefix, bool InPPDirective,
    unsigned Newlines, unsigned Spaces) {
  Changes.push_back(Change(
      true, SourceRange(Tok.getStartOfNonWhitespace().getLocWithOffset(Offset),
                        Tok.getStartOfNonWhitespace().getLocWithOffset(
                            Offset + ReplaceChars)),
      Spaces, Spaces, Newlines, PreviousPostfix, CurrentPrefix,
      // If we don't add a newline this change doesn't start a comment. Thus,
      // when we align line comments, we don't need to treat this change as one.
      // FIXME: We still need to take this change in account to properly
      // calculate the new length of the comment and to calculate the changes
      // for which to do the alignment when aligning comments.
      Tok.Type == TT_LineComment && Newlines > 0 ? tok::comment : tok::unknown,
      InPPDirective && !Tok.IsFirst));
}
Exemple #3
0
BlockCommandComment *Parser::parseBlockCommandArgs(
    BlockCommandComment *BC,
    TextTokenRetokenizer &Retokenizer,
    unsigned NumArgs) {
  typedef BlockCommandComment::Argument Argument;
  Argument *Args =
      new (Allocator.Allocate<Argument>(NumArgs)) Argument[NumArgs];
  unsigned ParsedArgs = 0;
  Token Arg;
  while (ParsedArgs < NumArgs && Retokenizer.lexWord(Arg)) {
    Args[ParsedArgs] = Argument(SourceRange(Arg.getLocation(),
                                            Arg.getEndLocation()),
                                Arg.getText());
    ParsedArgs++;
  }

  return S.actOnBlockCommandArgs(BC, llvm::makeArrayRef(Args, ParsedArgs));
}
Exemple #4
0
InlineCommandComment *Sema::actOnInlineCommand(SourceLocation CommandLocBegin,
                                               SourceLocation CommandLocEnd,
                                               StringRef CommandName,
                                               SourceLocation ArgLocBegin,
                                               SourceLocation ArgLocEnd,
                                               StringRef Arg) {
  typedef InlineCommandComment::Argument Argument;
  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
                                                     ArgLocEnd),
                                         Arg);

  return new (Allocator) InlineCommandComment(
                                  CommandLocBegin,
                                  CommandLocEnd,
                                  CommandName,
                                  getInlineCommandRenderKind(CommandName),
                                  llvm::makeArrayRef(A, 1));
}
Exemple #5
0
void InspectorStyleTextEditor::internalReplaceProperty(const InspectorStyleProperty& property, const String& newText, SourceRange* removedRange, unsigned* insertedLength)
{
    const SourceRange& range = property.sourceData.range;
    long replaceRangeStart = range.start;
    long replaceRangeEnd = range.end;
    const UChar* characters = m_styleText.characters();
    long newTextLength = newText.length();
    String finalNewText = newText;

    // Removing a property - remove preceding prefix.
    String fullPrefix = m_format.first + m_format.second;
    long fullPrefixLength = fullPrefix.length();
    if (!newTextLength && fullPrefixLength) {
        if (replaceRangeStart >= fullPrefixLength && m_styleText.substring(replaceRangeStart - fullPrefixLength, fullPrefixLength) == fullPrefix)
            replaceRangeStart -= fullPrefixLength;
    } else if (newTextLength) {
        if (isHTMLLineBreak(newText.characters()[newTextLength - 1])) {
            // Coalesce newlines of the original and new property values (to avoid a lot of blank lines while incrementally applying property values).
            bool foundNewline = false;
            bool isLastNewline = false;
            int i;
            int textLength = m_styleText.length();
            for (i = replaceRangeEnd; i < textLength && isSpaceOrNewline(characters[i]); ++i) {
                isLastNewline = isHTMLLineBreak(characters[i]);
                if (isLastNewline)
                    foundNewline = true;
                else if (foundNewline && !isLastNewline) {
                    replaceRangeEnd = i;
                    break;
                }
            }
            if (foundNewline && isLastNewline)
                replaceRangeEnd = i;
        }

        if (fullPrefixLength > replaceRangeStart || m_styleText.substring(replaceRangeStart - fullPrefixLength, fullPrefixLength) != fullPrefix)
            finalNewText.insert(fullPrefix, 0);
    }

    int replacedLength = replaceRangeEnd - replaceRangeStart;
    m_styleText.replace(replaceRangeStart, replacedLength, finalNewText);
    *removedRange = SourceRange(replaceRangeStart, replaceRangeEnd);
    *insertedLength = finalNewText.length();
}
void RedundantVoidArgCheck::processFunctionDecl(
    const MatchFinder::MatchResult &Result, const FunctionDecl *Function) {
  if (Function->isThisDeclarationADefinition()) {
    SourceLocation Start = Function->getBeginLoc();
    SourceLocation End = Function->getEndLoc();
    if (const Stmt *Body = Function->getBody()) {
      End = Body->getBeginLoc();
      if (End.isMacroID() &&
          Result.SourceManager->isAtStartOfImmediateMacroExpansion(End))
        End = Result.SourceManager->getExpansionLoc(End);
      End = End.getLocWithOffset(-1);
    }
    removeVoidArgumentTokens(Result, SourceRange(Start, End),
                             "function definition");
  } else {
    removeVoidArgumentTokens(Result, Function->getSourceRange(),
                             "function declaration");
  }
}
void IncludeSorter::AddInclude(StringRef FileName, bool IsAngled,
                               SourceLocation HashLocation,
                               SourceLocation EndLocation) {
  int Offset = FindNextLine(SourceMgr->getCharacterData(EndLocation));

  // Record the relevant location information for this inclusion directive.
  IncludeLocations[FileName].push_back(
      SourceRange(HashLocation, EndLocation.getLocWithOffset(Offset)));
  SourceLocations.push_back(IncludeLocations[FileName].back());

  // Stop if this inclusion is a duplicate.
  if (IncludeLocations[FileName].size() > 1)
    return;

  // Add the included file's name to the appropriate bucket.
  IncludeKinds Kind =
      DetermineIncludeKind(CanonicalFile, FileName, IsAngled, Style);
  if (Kind != IK_InvalidInclude)
    IncludeBucket[Kind].push_back(FileName.str());
}
// 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;
}
void LambdaFunctionNameCheck::check(const MatchFinder::MatchResult &Result) {
  const auto *E = Result.Nodes.getNodeAs<PredefinedExpr>("E");
  if (E->getIdentType() != PredefinedExpr::Func &&
      E->getIdentType() != PredefinedExpr::Function) {
    // We don't care about other PredefinedExprs.
    return;
  }
  if (E->getLocation().isMacroID()) {
    auto ER =
        Result.SourceManager->getImmediateExpansionRange(E->getLocation());
    if (SuppressMacroExpansions.find(SourceRange(ER.first, ER.second)) !=
        SuppressMacroExpansions.end()) {
      // This is a macro expansion for which we should not warn.
      return;
    }
  }
  diag(E->getLocation(),
       "inside a lambda, '%0' expands to the name of the function call "
       "operator; consider capturing the name of the enclosing function "
       "explicitly")
      << PredefinedExpr::getIdentTypeName(E->getIdentType());
}
Decl *Sema::ActOnExternalEntityDecl(ASTContext &C, QualType T,
                                    SourceLocation IDLoc, const IdentifierInfo *IDInfo) {
  SourceLocation TypeLoc;
  VarDecl *ArgumentExternal = nullptr;
  if (auto Prev = LookupIdentifier(IDInfo)) {
    auto Quals = getDeclQualifiers(Prev);
    if(Quals.hasAttributeSpec(Qualifiers::AS_external)) {
      Diags.Report(IDLoc, diag::err_duplicate_attr_spec)
        << DeclSpec::getSpecifierName(Qualifiers::AS_external);
      return Prev;
    }

    // apply EXTERNAL to an unused symbol or an argument.
    auto VD = dyn_cast<VarDecl>(Prev);
    if(VD && (VD->isUnusedSymbol() || VD->isArgument()) ) {
      T = VD->getType();
      TypeLoc = VD->getLocation();
      CurContext->removeDecl(VD);
      if(VD->isArgument())
        ArgumentExternal = VD;
    } else {
      DiagnoseRedefinition(IDLoc, IDInfo, Prev);
      return nullptr;
    }
  }
  if(T.isNull())
    T = C.VoidTy;

  DeclarationNameInfo DeclName(IDInfo,IDLoc);
  auto Decl = FunctionDecl::Create(C, ArgumentExternal? FunctionDecl::ExternalArgument :
                                                        FunctionDecl::External,
                                   CurContext, DeclName, T);
  SetFunctionType(Decl, T, TypeLoc, SourceRange()); //FIXME: proper loc, and range
  CurContext->addDecl(Decl);
  if(ArgumentExternal)
    ArgumentExternal->setType(C.getFunctionType(Decl));
  return Decl;
}
Exemple #11
0
void WhitespaceManager::replaceWhitespace(const AnnotatedToken &Tok,
                                          unsigned Newlines, unsigned Spaces,
                                          unsigned StartOfTokenColumn,
                                          bool InPPDirective) {
  Changes.push_back(Change(
      true, SourceRange(Tok.FormatTok.WhiteSpaceStart,
                        Tok.FormatTok.WhiteSpaceStart.getLocWithOffset(
                            Tok.FormatTok.WhiteSpaceLength)),
      Spaces, StartOfTokenColumn, Newlines, "", "", Tok.FormatTok.Tok.getKind(),
      InPPDirective && !Tok.FormatTok.IsFirst));

  // Align line comments if they are trailing or if they continue other
  // trailing comments.
  // FIXME: Pull this out and generalize so it works the same way in broken
  // comments and unbroken comments with trailing whitespace.
  if (Tok.isTrailingComment()) {
    SourceLocation TokenEndLoc = Tok.FormatTok.getStartOfNonWhitespace()
        .getLocWithOffset(Tok.FormatTok.TokenLength);
    // Remove the comment's trailing whitespace.
    if (Tok.FormatTok.TrailingWhiteSpaceLength != 0)
      Replaces.insert(tooling::Replacement(
          SourceMgr, TokenEndLoc, Tok.FormatTok.TrailingWhiteSpaceLength, ""));
  }
}
Exemple #12
0
StmtResult Sema::ActOnDATA(ASTContext &C, SourceLocation Loc,
                           ArrayRef<Expr*> Objects,
                           ArrayRef<Expr*> Values,
                           Expr *StmtLabel) {
  DataValueIterator ValuesIt(Values);
  DataStmtEngine LHSVisitor(ValuesIt, *this, Diags, Loc);
  for(auto I : Objects) {
    LHSVisitor.Visit(I);
    if(LHSVisitor.IsDone()) break;
  }

  if(!ValuesIt.isEmpty()) {
    // more items than values
    auto FirstVal = ValuesIt.getActualValue();
    auto LastVal = ValuesIt.getActualLastValue();
    Diags.Report(FirstVal->getLocation(), diag::err_data_stmt_too_many_values)
      << SourceRange(FirstVal->getLocStart(), LastVal->getLocEnd());
  }

  auto Result = DataStmt::Create(C, Loc, Objects, Values,
                                 StmtLabel);
  if(StmtLabel) DeclareStatementLabel(StmtLabel, Result);
  return Result;
}
Exemple #13
0
  bool DeclExtractor::CheckTagDeclaration(TagDecl* NewTD,
                                          LookupResult& Previous){
    // If the decl is already known invalid, don't check it.
    if (NewTD->isInvalidDecl())
      return false;

    IdentifierInfo* Name = NewTD->getIdentifier();
    // If this is not a definition, it must have a name.
    assert((Name != 0 || NewTD->isThisDeclarationADefinition()) &&
           "Nameless record must be a definition!");

    // Figure out the underlying type if this a enum declaration. We need to do
    // this early, because it's needed to detect if this is an incompatible
    // redeclaration.

    TagDecl::TagKind Kind = NewTD->getTagKind();
    bool Invalid = false;
    assert(NewTD->getNumTemplateParameterLists() == 0
           && "Cannot handle that yet!");
    bool isExplicitSpecialization = false;

    if (Kind == TTK_Enum) {
      EnumDecl* ED = cast<EnumDecl>(NewTD);
      bool ScopedEnum = ED->isScoped();
      const QualType QT = ED->getIntegerType();

      if (QT.isNull() && ScopedEnum)
        // No underlying type explicitly specified, or we failed to parse the
        // type, default to int.
        ; //EnumUnderlying = m_Context->IntTy.getTypePtr();
      else if (!QT.isNull()) {
        // C++0x 7.2p2: The type-specifier-seq of an enum-base shall name an
        // integral type; any cv-qualification is ignored.

        SourceLocation UnderlyingLoc;
        TypeSourceInfo* TI = 0;
        if ((TI = ED->getIntegerTypeSourceInfo()))
          UnderlyingLoc = TI->getTypeLoc().getBeginLoc();

        if (!QT->isDependentType() && !QT->isIntegralType(*m_Context)) {
          m_Sema->Diag(UnderlyingLoc, diag::err_enum_invalid_underlying)
            << QT;
        }
        if (TI)
          m_Sema->DiagnoseUnexpandedParameterPack(UnderlyingLoc, TI,
                                                Sema::UPPC_FixedUnderlyingType);
      }
    }

    DeclContext *SearchDC = m_Sema->CurContext;
    DeclContext *DC = m_Sema->CurContext;
    //bool isStdBadAlloc = false;
    SourceLocation NameLoc = NewTD->getLocation();
    // if (Name && SS.isNotEmpty()) {
    //   // We have a nested-name tag ('struct foo::bar').

    //   // Check for invalid 'foo::'.
    //   if (SS.isInvalid()) {
    //     Name = 0;
    //     goto CreateNewDecl;
    //   }

    //   // If this is a friend or a reference to a class in a dependent
    //   // context, don't try to make a decl for it.
    //   if (TUK == TUK_Friend || TUK == TUK_Reference) {
    //     DC = computeDeclContext(SS, false);
    //     if (!DC) {
    //       IsDependent = true;
    //       return 0;
    //     }
    //   } else {
    //     DC = computeDeclContext(SS, true);
    //     if (!DC) {
    //       Diag(SS.getRange().getBegin(),
    //            diag::err_dependent_nested_name_spec)
    //         << SS.getRange();
    //       return 0;
    //     }
    //   }

    //   if (RequireCompleteDeclContext(SS, DC))
    //     return 0;

    //   SearchDC = DC;
    //   // Look-up name inside 'foo::'.
    //   LookupQualifiedName(Previous, DC);

    //   if (Previous.isAmbiguous())
    //     return 0;

    //   if (Previous.empty()) {
    //     // Name lookup did not find anything. However, if the
    //     // nested-name-specifier refers to the current instantiation,
    //     // and that current instantiation has any dependent base
    //     // classes, we might find something at instantiation time: treat
    //     // this as a dependent elaborated-type-specifier.
    //     // But this only makes any sense for reference-like lookups.
    //     if (Previous.wasNotFoundInCurrentInstantiation() &&
    //         (TUK == TUK_Reference || TUK == TUK_Friend)) {
    //       IsDependent = true;
    //       return 0;
    //     }

    //     // A tag 'foo::bar' must already exist.
    //     Diag(NameLoc, diag::err_not_tag_in_scope)
    //       << Kind << Name << DC << SS.getRange();
    //     Name = 0;
    //     Invalid = true;
    //   goto CreateNewDecl;
    // }
    //} else
    if (Name) {
      // If this is a named struct, check to see if there was a previous forward
      // declaration or definition.
      // FIXME: We're looking into outer scopes here, even when we
      // shouldn't be. Doing so can result in ambiguities that we
      // shouldn't be diagnosing.

      //LookupName(Previous, S);

      if (Previous.isAmbiguous()) {
        LookupResult::Filter F = Previous.makeFilter();
        while (F.hasNext()) {
          NamedDecl *ND = F.next();
          if (ND->getDeclContext()->getRedeclContext() != SearchDC)
            F.erase();
        }
        F.done();
      }

      // Note:  there used to be some attempt at recovery here.
      if (Previous.isAmbiguous()) {
        return false;
      }

      if (!m_Sema->getLangOpts().CPlusPlus) {
        // FIXME: This makes sure that we ignore the contexts associated
        // with C structs, unions, and enums when looking for a matching
        // tag declaration or definition. See the similar lookup tweak
        // in Sema::LookupName; is there a better way to deal with this?
        while (isa<RecordDecl>(SearchDC) || isa<EnumDecl>(SearchDC))
          SearchDC = SearchDC->getParent();
      }
    } else if (m_Sema->getScopeForContext(m_Sema->CurContext)
               ->isFunctionPrototypeScope()) {
      // If this is an enum declaration in function prototype scope, set its
      // initial context to the translation unit.
      SearchDC = m_Context->getTranslationUnitDecl();
    }

    if (Previous.isSingleResult() &&
        Previous.getFoundDecl()->isTemplateParameter()) {
      // Maybe we will complain about the shadowed template parameter.
      m_Sema->DiagnoseTemplateParameterShadow(NameLoc, Previous.getFoundDecl());
      // Just pretend that we didn't see the previous declaration.
      Previous.clear();
    }

    if (m_Sema->getLangOpts().CPlusPlus && Name && DC && m_Sema->StdNamespace
        && DC->Equals(m_Sema->getStdNamespace()) && Name->isStr("bad_alloc")) {
      // This is a declaration of or a reference to "std::bad_alloc".
      //isStdBadAlloc = true;

      if (Previous.empty() && m_Sema->StdBadAlloc) {
        // std::bad_alloc has been implicitly declared (but made invisible to
        // name lookup). Fill in this implicit declaration as the previous
        // declaration, so that the declarations get chained appropriately.
        Previous.addDecl(m_Sema->getStdBadAlloc());
      }
    }

    if (!Previous.empty()) {
      NamedDecl *PrevDecl = (*Previous.begin())->getUnderlyingDecl();

      // It's okay to have a tag decl in the same scope as a typedef
      // which hides a tag decl in the same scope.  Finding this
      // insanity with a redeclaration lookup can only actually happen
      // in C++.
      //
      // This is also okay for elaborated-type-specifiers, which is
      // technically forbidden by the current standard but which is
      // okay according to the likely resolution of an open issue;
      // see http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#407
      if (m_Sema->getLangOpts().CPlusPlus) {
        if (TypedefNameDecl *TD = dyn_cast<TypedefNameDecl>(PrevDecl)) {
          if (const TagType *TT = TD->getUnderlyingType()->getAs<TagType>()) {
            TagDecl *Tag = TT->getDecl();
            if (Tag->getDeclName() == Name &&
                Tag->getDeclContext()->getRedeclContext()
                ->Equals(TD->getDeclContext()->getRedeclContext())) {
              PrevDecl = Tag;
              Previous.clear();
              Previous.addDecl(Tag);
              Previous.resolveKind();
            }
          }
        }
      }

      if (TagDecl *PrevTagDecl = dyn_cast<TagDecl>(PrevDecl)) {
        // If this is a use of a previous tag, or if the tag is already declared
        // in the same scope (so that the definition/declaration completes or
        // rementions the tag), reuse the decl.
        if (m_Sema->isDeclInScope(PrevDecl, SearchDC,
                                 m_Sema->getScopeForContext(m_Sema->CurContext),
                                  isExplicitSpecialization)) {
          // Make sure that this wasn't declared as an enum and now used as a
          // struct or something similar.
          SourceLocation KWLoc = NewTD->getLocStart();
          if (!m_Sema->isAcceptableTagRedeclaration(PrevTagDecl, Kind,
                                          NewTD->isThisDeclarationADefinition(),
                                                    KWLoc, *Name)) {
            bool SafeToContinue
              = (PrevTagDecl->getTagKind() != TTK_Enum && Kind != TTK_Enum);

            if (SafeToContinue)
              m_Sema->Diag(KWLoc, diag::err_use_with_wrong_tag)
                << Name
                << FixItHint::CreateReplacement(SourceRange(KWLoc),
                                                PrevTagDecl->getKindName());
            else
              m_Sema->Diag(KWLoc, diag::err_use_with_wrong_tag) << Name;
            m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use);

            if (SafeToContinue)
              Kind = PrevTagDecl->getTagKind();
            else {
              // Recover by making this an anonymous redefinition.
              Name = 0;
              Previous.clear();
              Invalid = true;
            }
          }

          if (Kind == TTK_Enum && PrevTagDecl->getTagKind() == TTK_Enum) {
            const EnumDecl *NewEnum = cast<EnumDecl>(NewTD);
            const EnumDecl *PrevEnum = cast<EnumDecl>(PrevTagDecl);

            // All conflicts with previous declarations are recovered by
            // returning the previous declaration.
            if (NewEnum->isScoped() != PrevEnum->isScoped()) {
              m_Sema->Diag(KWLoc, diag::err_enum_redeclare_scoped_mismatch)
                << PrevEnum->isScoped();
              m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use);

              return false;
            }
            else if (PrevEnum->isFixed()) {
              QualType T = NewEnum->getIntegerType();

              if (!m_Context->hasSameUnqualifiedType(T,
                                                  PrevEnum->getIntegerType())) {
                m_Sema->Diag(NameLoc.isValid() ? NameLoc : KWLoc,
                             diag::err_enum_redeclare_type_mismatch)
                  << T
                  << PrevEnum->getIntegerType();
                m_Sema->Diag(PrevTagDecl->getLocation(),
                             diag::note_previous_use);

                return false;
              }
            }
            else if (NewEnum->isFixed() != PrevEnum->isFixed()) {
              m_Sema->Diag(KWLoc, diag::err_enum_redeclare_fixed_mismatch)
                << PrevEnum->isFixed();
              m_Sema->Diag(PrevTagDecl->getLocation(), diag::note_previous_use);

              return false;
            }
          }

          if (!Invalid) {
            // If this is a use, just return the declaration we found.

            // Diagnose attempts to redefine a tag.
            if (NewTD->isThisDeclarationADefinition()) {
              if (TagDecl* Def = PrevTagDecl->getDefinition()) {
                // If we're defining a specialization and the previous
                // definition is from an implicit instantiation, don't emit an
                // error here; we'll catch this in the general case below.
                if (!isExplicitSpecialization ||
                    !isa<CXXRecordDecl>(Def) ||
                    cast<CXXRecordDecl>(Def)->getTemplateSpecializationKind()
                    == TSK_ExplicitSpecialization) {
                  m_Sema->Diag(NameLoc, diag::err_redefinition) << Name;
                  m_Sema->Diag(Def->getLocation(),
                               diag::note_previous_definition);
                  // If this is a redefinition, recover by making this
                  // struct be anonymous, which will make any later
                  // references get the previous definition.
                  Name = 0;
                  Previous.clear();
                  Invalid = true;
                }
              } else {
                // If the type is currently being defined, complain
                // about a nested redefinition.
                const TagType *Tag
                  = cast<TagType>(m_Context->getTagDeclType(PrevTagDecl));
                if (Tag->isBeingDefined()) {
                  m_Sema->Diag(NameLoc, diag::err_nested_redefinition) << Name;
                  m_Sema->Diag(PrevTagDecl->getLocation(),
                               diag::note_previous_definition);
                  Name = 0;
                  Previous.clear();
                  Invalid = true;
                }
              }

              // Okay, this is definition of a previously declared or referenced
              // tag PrevDecl. We're going to create a new Decl for it.
            }
          }
          // If we get here we have (another) forward declaration or we
          // have a definition.  Just create a new decl.

        } else {
          // If we get here, this is a definition of a new tag type in a nested
          // scope, e.g. "struct foo; void bar() { struct foo; }", just create a
          // new decl/type.  We set PrevDecl to NULL so that the entities
          // have distinct types.
          Previous.clear();
        }
        // If we get here, we're going to create a new Decl. If PrevDecl
        // is non-NULL, it's a definition of the tag declared by
        // PrevDecl. If it's NULL, we have a new definition.


        // Otherwise, PrevDecl is not a tag, but was found with tag
        // lookup.  This is only actually possible in C++, where a few
        // things like templates still live in the tag namespace.
      } else {
        assert(m_Sema->getLangOpts().CPlusPlus);

        // Diagnose if the declaration is in scope.
        if (!m_Sema->isDeclInScope(PrevDecl, SearchDC,
                                 m_Sema->getScopeForContext(m_Sema->CurContext),
                                   isExplicitSpecialization)) {
          // do nothing

          // Otherwise it's a declaration.  Call out a particularly common
          // case here.
        } else if (TypedefNameDecl *TND = dyn_cast<TypedefNameDecl>(PrevDecl)) {
          unsigned Kind = 0;
          if (isa<TypeAliasDecl>(PrevDecl)) Kind = 1;
          m_Sema->Diag(NameLoc, diag::err_tag_definition_of_typedef)
            << Name << Kind << TND->getUnderlyingType();
          m_Sema->Diag(PrevDecl->getLocation(),
                       diag::note_previous_decl) << PrevDecl;
          Invalid = true;

          // Otherwise, diagnose.
        } else {
          // The tag name clashes with something else in the target scope,
          // issue an error and recover by making this tag be anonymous.
          m_Sema->Diag(NameLoc, diag::err_redefinition_different_kind) << Name;
          m_Sema->Diag(PrevDecl->getLocation(), diag::note_previous_definition);
          Name = 0;
          Invalid = true;
        }

        // The existing declaration isn't relevant to us; we're in a
        // new scope, so clear out the previous declaration.
        Previous.clear();
      }
    }
    if (Invalid) {
      return false;
    }

    return true;
  }
Exemple #14
0
 virtual SourceRange getRange(const TypeLoc &Node) {
   TemplateSpecializationTypeLoc T =
       Node.getUnqualifiedLoc().castAs<TemplateSpecializationTypeLoc>();
   assert(!T.isNull());
   return SourceRange(T.getLAngleLoc(), T.getRAngleLoc());
 }
Exemple #15
0
 virtual SourceRange getRange(const TypeLoc &Node) {
   UnaryTransformTypeLoc T =
       Node.getUnqualifiedLoc().castAs<UnaryTransformTypeLoc>();
   assert(!T.isNull());
   return SourceRange(T.getLParenLoc(), T.getRParenLoc());
 }
Exemple #16
0
SourceRange Cursor::getExtent() const
{
   return SourceRange(clang().getCursorExtent(cursor_));
}
void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) {
  const NamespaceDecl *ND = Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
  const SourceManager &Sources = *Result.SourceManager;

  if (!locationsInSameFile(Sources, ND->getLocStart(), ND->getRBraceLoc()))
    return;

  // Don't require closing comments for namespaces spanning less than certain
  // number of lines.
  unsigned StartLine = Sources.getSpellingLineNumber(ND->getLocStart());
  unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc());
  if (EndLine - StartLine + 1 <= ShortNamespaceLines)
    return;

  // Find next token after the namespace closing brace.
  SourceLocation AfterRBrace = ND->getRBraceLoc().getLocWithOffset(1);
  SourceLocation Loc = AfterRBrace;
  Token Tok;
  // Skip whitespace until we find the next token.
  while (Lexer::getRawToken(Loc, Tok, Sources, Result.Context->getLangOpts()) ||
         Tok.is(tok::semi)) {
    Loc = Loc.getLocWithOffset(1);
  }
  if (!locationsInSameFile(Sources, ND->getRBraceLoc(), Loc))
    return;

  bool NextTokenIsOnSameLine = Sources.getSpellingLineNumber(Loc) == EndLine;
  // If we insert a line comment before the token in the same line, we need
  // to insert a line break.
  bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof);

  SourceRange OldCommentRange(AfterRBrace, AfterRBrace);
  std::string Message = "%0 not terminated with a closing comment";

  // Try to find existing namespace closing comment on the same line.
  if (Tok.is(tok::comment) && NextTokenIsOnSameLine) {
    StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
    SmallVector<StringRef, 7> Groups;
    if (NamespaceCommentPattern.match(Comment, &Groups)) {
      StringRef NamespaceNameInComment = Groups.size() > 5 ? Groups[5] : "";
      StringRef Anonymous = Groups.size() > 3 ? Groups[3] : "";

      // Check if the namespace in the comment is the same.
      if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) ||
          (ND->getNameAsString() == NamespaceNameInComment &&
           Anonymous.empty())) {
        // FIXME: Maybe we need a strict mode, where we always fix namespace
        // comments with different format.
        return;
      }

      // Otherwise we need to fix the comment.
      NeedLineBreak = Comment.startswith("/*");
      OldCommentRange =
          SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
      Message =
          (llvm::Twine(
               "%0 ends with a comment that refers to a wrong namespace '") +
           NamespaceNameInComment + "'").str();
    } else if (Comment.startswith("//")) {
      // Assume that this is an unrecognized form of a namespace closing line
      // comment. Replace it.
      NeedLineBreak = false;
      OldCommentRange =
          SourceRange(AfterRBrace, Loc.getLocWithOffset(Tok.getLength()));
      Message = "%0 ends with an unrecognized comment";
    }
    // If it's a block comment, just move it to the next line, as it can be
    // multi-line or there may be other tokens behind it.
  }

  std::string NamespaceName =
      ND->isAnonymousNamespace()
          ? "anonymous namespace"
          : ("namespace '" + ND->getNameAsString() + "'");

  diag(AfterRBrace, Message)
      << NamespaceName << FixItHint::CreateReplacement(
                              CharSourceRange::getCharRange(OldCommentRange),
                              std::string(SpacesBeforeComments, ' ') +
                                  getNamespaceComment(ND, NeedLineBreak));
  diag(ND->getLocation(), "%0 starts here", DiagnosticIDs::Note)
      << NamespaceName;
}
Exemple #18
0
HTMLStartTagComment *Parser::parseHTMLStartTag() {
  assert(Tok.is(tok::html_start_tag));
  HTMLStartTagComment *HST =
      S.actOnHTMLStartTagStart(Tok.getLocation(),
                               Tok.getHTMLTagStartName());
  consumeToken();

  SmallVector<HTMLStartTagComment::Attribute, 2> Attrs;
  while (true) {
    switch (Tok.getKind()) {
    case tok::html_ident: {
      Token Ident = Tok;
      consumeToken();
      if (Tok.isNot(tok::html_equals)) {
        Attrs.push_back(HTMLStartTagComment::Attribute(Ident.getLocation(),
                                                       Ident.getHTMLIdent()));
        continue;
      }
      Token Equals = Tok;
      consumeToken();
      if (Tok.isNot(tok::html_quoted_string)) {
        Diag(Tok.getLocation(),
             diag::warn_doc_html_start_tag_expected_quoted_string)
          << SourceRange(Equals.getLocation());
        Attrs.push_back(HTMLStartTagComment::Attribute(Ident.getLocation(),
                                                       Ident.getHTMLIdent()));
        while (Tok.is(tok::html_equals) ||
               Tok.is(tok::html_quoted_string))
          consumeToken();
        continue;
      }
      Attrs.push_back(HTMLStartTagComment::Attribute(
                              Ident.getLocation(),
                              Ident.getHTMLIdent(),
                              Equals.getLocation(),
                              SourceRange(Tok.getLocation(),
                                          Tok.getEndLocation()),
                              Tok.getHTMLQuotedString()));
      consumeToken();
      continue;
    }

    case tok::html_greater:
      HST = S.actOnHTMLStartTagFinish(HST,
                                      copyArray(llvm::makeArrayRef(Attrs)),
                                      Tok.getLocation(),
                                      /* IsSelfClosing = */ false);
      consumeToken();
      return HST;

    case tok::html_slash_greater:
      HST = S.actOnHTMLStartTagFinish(HST,
                                      copyArray(llvm::makeArrayRef(Attrs)),
                                      Tok.getLocation(),
                                      /* IsSelfClosing = */ true);
      consumeToken();
      return HST;

    case tok::html_equals:
    case tok::html_quoted_string:
      Diag(Tok.getLocation(),
           diag::warn_doc_html_start_tag_expected_ident_or_greater);
      while (Tok.is(tok::html_equals) ||
             Tok.is(tok::html_quoted_string))
        consumeToken();
      if (Tok.is(tok::html_ident) ||
          Tok.is(tok::html_greater) ||
          Tok.is(tok::html_slash_greater))
        continue;

      return S.actOnHTMLStartTagFinish(HST,
                                       copyArray(llvm::makeArrayRef(Attrs)),
                                       SourceLocation(),
                                       /* IsSelfClosing = */ false);

    default:
      // Not a token from an HTML start tag.  Thus HTML tag prematurely ended.
      HST = S.actOnHTMLStartTagFinish(HST,
                                      copyArray(llvm::makeArrayRef(Attrs)),
                                      SourceLocation(),
                                      /* IsSelfClosing = */ false);
      bool StartLineInvalid;
      const unsigned StartLine = SourceMgr.getPresumedLineNumber(
                                                  HST->getLocation(),
                                                  &StartLineInvalid);
      bool EndLineInvalid;
      const unsigned EndLine = SourceMgr.getPresumedLineNumber(
                                                  Tok.getLocation(),
                                                  &EndLineInvalid);
      if (StartLineInvalid || EndLineInvalid || StartLine == EndLine)
        Diag(Tok.getLocation(),
             diag::warn_doc_html_start_tag_expected_ident_or_greater)
          << HST->getSourceRange();
      else {
        Diag(Tok.getLocation(),
             diag::warn_doc_html_start_tag_expected_ident_or_greater);
        Diag(HST->getLocation(), diag::note_doc_html_tag_started_here)
          << HST->getSourceRange();
      }
      return HST;
    }
  }
}
  Expr* ValueExtractionSynthesizer::SynthesizeSVRInit(Expr* E) {
    if (!m_gClingVD)
      FindAndCacheRuntimeDecls();

    // Build a reference to gCling
    ExprResult gClingDRE
      = m_Sema->BuildDeclRefExpr(m_gClingVD, m_Context->VoidPtrTy,
                                 VK_RValue, SourceLocation());
    // We have the wrapper as Sema's CurContext
    FunctionDecl* FD = cast<FunctionDecl>(m_Sema->CurContext);

    ExprWithCleanups* Cleanups = 0;
    // In case of ExprWithCleanups we need to extend its 'scope' to the call.
    if (E && isa<ExprWithCleanups>(E)) {
      Cleanups = cast<ExprWithCleanups>(E);
      E = Cleanups->getSubExpr();
    }

    // Build a reference to Value* in the wrapper, should be
    // the only argument of the wrapper.
    SourceLocation locStart = (E) ? E->getLocStart() : FD->getLocStart();
    SourceLocation locEnd = (E) ? E->getLocEnd() : FD->getLocEnd();
    ExprResult wrapperSVRDRE
      = m_Sema->BuildDeclRefExpr(FD->getParamDecl(0), m_Context->VoidPtrTy,
                                 VK_RValue, locStart);
    QualType ETy = (E) ? E->getType() : m_Context->VoidTy;
    QualType desugaredTy = ETy.getDesugaredType(*m_Context);

    // The expr result is transported as reference, pointer, array, float etc
    // based on the desugared type. We should still expose the typedef'ed
    // (sugared) type to the cling::Value.
    if (desugaredTy->isRecordType() && E->getValueKind() == VK_LValue) {
      // returning a lvalue (not a temporary): the value should contain
      // a reference to the lvalue instead of copying it.
      desugaredTy = m_Context->getLValueReferenceType(desugaredTy);
      ETy = m_Context->getLValueReferenceType(ETy);
    }
    Expr* ETyVP
      = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
                                             (uint64_t)ETy.getAsOpaquePtr());
    Expr* ETransaction
      = utils::Synthesize::CStyleCastPtrExpr(m_Sema, m_Context->VoidPtrTy,
                                             (uint64_t)getTransaction());

    llvm::SmallVector<Expr*, 6> CallArgs;
    CallArgs.push_back(gClingDRE.take());
    CallArgs.push_back(wrapperSVRDRE.take());
    CallArgs.push_back(ETyVP);
    CallArgs.push_back(ETransaction);

    ExprResult Call;
    SourceLocation noLoc;
    if (desugaredTy->isVoidType()) {
      // In cases where the cling::Value gets reused we need to reset the
      // previous settings to void.
      // We need to synthesize setValueNoAlloc(...), E, because we still need
      // to run E.

      // FIXME: Suboptimal: this discards the already created AST nodes.
      QualType vpQT = m_Context->VoidPtrTy;
      QualType vQT = m_Context->VoidTy;
      Expr* vpQTVP
        = utils::Synthesize::CStyleCastPtrExpr(m_Sema, vpQT,
                                               (uint64_t)vQT.getAsOpaquePtr());
      CallArgs[2] = vpQTVP;


      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   locStart, CallArgs, locEnd);

      if (E)
        Call = m_Sema->CreateBuiltinBinOp(locStart, BO_Comma, Call.take(), E);

    }
    else if (desugaredTy->isRecordType() || desugaredTy->isConstantArrayType()){
      // 2) object types :
      // check existance of copy constructor before call
      if (!availableCopyConstructor(desugaredTy, m_Sema))
        return E;
      // call new (setValueWithAlloc(gCling, &SVR, ETy)) (E)
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedWithAlloc,
                                   locStart, CallArgs, locEnd);
      Expr* placement = Call.take();
      if (const ConstantArrayType* constArray
          = dyn_cast<ConstantArrayType>(desugaredTy.getTypePtr())) {
        CallArgs.clear();
        CallArgs.push_back(E);
        CallArgs.push_back(placement);
        uint64_t arrSize
          = m_Context->getConstantArrayElementCount(constArray);
        Expr* arrSizeExpr
          = utils::Synthesize::IntegerLiteralExpr(*m_Context, arrSize);

        CallArgs.push_back(arrSizeExpr);
        // 2.1) arrays:
        // call copyArray(T* src, void* placement, int size)
        Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedCopyArray,
                                     locStart, CallArgs, locEnd);

      }
      else {
        TypeSourceInfo* ETSI
          = m_Context->getTrivialTypeSourceInfo(ETy, noLoc);

        Call = m_Sema->BuildCXXNew(E->getSourceRange(),
                                   /*useGlobal ::*/true,
                                   /*placementLParen*/ noLoc,
                                   MultiExprArg(placement),
                                   /*placementRParen*/ noLoc,
                                   /*TypeIdParens*/ SourceRange(),
                                   /*allocType*/ ETSI->getType(),
                                   /*allocTypeInfo*/ETSI,
                                   /*arraySize*/0,
                                   /*directInitRange*/E->getSourceRange(),
                                   /*initializer*/E,
                                   /*mayContainAuto*/false
                                   );
      }
    }
    else if (desugaredTy->isIntegralOrEnumerationType()
             || desugaredTy->isReferenceType()
             || desugaredTy->isPointerType()
             || desugaredTy->isFloatingType()) {
      if (desugaredTy->isIntegralOrEnumerationType()) {
        // 1)  enum, integral, float, double, referece, pointer types :
        //      call to cling::internal::setValueNoAlloc(...);

        // If the type is enum or integral we need to force-cast it into
        // uint64 in order to pick up the correct overload.
        if (desugaredTy->isIntegralOrEnumerationType()) {
          QualType UInt64Ty = m_Context->UnsignedLongLongTy;
          TypeSourceInfo* TSI
            = m_Context->getTrivialTypeSourceInfo(UInt64Ty, noLoc);
          Expr* castedE
            = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
          CallArgs.push_back(castedE);
        }
      }
      else if (desugaredTy->isReferenceType()) {
        // we need to get the address of the references
        Expr* AddrOfE = m_Sema->BuildUnaryOp(/*Scope*/0, noLoc, UO_AddrOf,
                                             E).take();
        CallArgs.push_back(AddrOfE);
      }
      else if (desugaredTy->isPointerType()) {
        // function pointers need explicit void* cast.
        QualType VoidPtrTy = m_Context->VoidPtrTy;
        TypeSourceInfo* TSI
          = m_Context->getTrivialTypeSourceInfo(VoidPtrTy, noLoc);
        Expr* castedE
          = m_Sema->BuildCStyleCastExpr(noLoc, TSI, noLoc, E).take();
        CallArgs.push_back(castedE);
      }
      else if (desugaredTy->isFloatingType()) {
        // floats and double will fall naturally in the correct
        // case, because of the overload resolution.
        CallArgs.push_back(E);
      }
      Call = m_Sema->ActOnCallExpr(/*Scope*/0, m_UnresolvedNoAlloc,
                                   locStart, CallArgs, locEnd);
    }
    else
      assert(0 && "Unhandled code path?");

    assert(!Call.isInvalid() && "Invalid Call");

    // Extend the scope of the temporary cleaner if applicable.
    if (Cleanups) {
      Cleanups->setSubExpr(Call.take());
      Cleanups->setValueKind(Call.take()->getValueKind());
      Cleanups->setType(Call.take()->getType());
      return Cleanups;
    }
    return Call.take();
  }
Exemple #20
0
void RemoveStatement(clang::Rewriter& TheRewriter, clang::CallExpr const * const Statement)
{
    ExpandSourceRange SourceRange{TheRewriter};
    TheRewriter.RemoveText(SourceRange(Statement->getSourceRange()));
}
void NamespaceCommentCheck::check(const MatchFinder::MatchResult &Result) {
  const NamespaceDecl *ND = Result.Nodes.getNodeAs<NamespaceDecl>("namespace");
  const SourceManager &Sources = *Result.SourceManager;

  if (!locationsInSameFile(Sources, ND->getLocStart(), ND->getRBraceLoc()))
    return;

  // Don't require closing comments for namespaces spanning less than certain
  // number of lines.
  unsigned StartLine = Sources.getSpellingLineNumber(ND->getLocStart());
  unsigned EndLine = Sources.getSpellingLineNumber(ND->getRBraceLoc());
  if (EndLine - StartLine + 1 <= ShortNamespaceLines)
    return;

  // Find next token after the namespace closing brace.
  SourceLocation AfterRBrace = ND->getRBraceLoc().getLocWithOffset(1);
  SourceLocation Loc = AfterRBrace;
  Token Tok;
  // Skip whitespace until we find the next token.
  while (Lexer::getRawToken(Loc, Tok, Sources, Result.Context->getLangOpts())) {
    Loc = Loc.getLocWithOffset(1);
  }
  if (!locationsInSameFile(Sources, ND->getRBraceLoc(), Loc))
    return;

  bool NextTokenIsOnSameLine = Sources.getSpellingLineNumber(Loc) == EndLine;
  // If we insert a line comment before the token in the same line, we need
  // to insert a line break.
  bool NeedLineBreak = NextTokenIsOnSameLine && Tok.isNot(tok::eof);

  // Try to find existing namespace closing comment on the same line.
  if (Tok.is(tok::comment) && NextTokenIsOnSameLine) {
    StringRef Comment(Sources.getCharacterData(Loc), Tok.getLength());
    SmallVector<StringRef, 6> Groups;
    if (NamespaceCommentPattern.match(Comment, &Groups)) {
      StringRef NamespaceNameInComment = Groups.size() >= 6 ? Groups[5] : "";

      // Check if the namespace in the comment is the same.
      if ((ND->isAnonymousNamespace() && NamespaceNameInComment.empty()) ||
          ND->getNameAsString() == NamespaceNameInComment) {
        // FIXME: Maybe we need a strict mode, where we always fix namespace
        // comments with different format.
        return;
      }

      // Otherwise we need to fix the comment.
      NeedLineBreak = Comment.startswith("/*");
      CharSourceRange OldCommentRange = CharSourceRange::getCharRange(
          SourceRange(Loc, Loc.getLocWithOffset(Tok.getLength())));
      diag(Loc, "namespace closing comment refers to a wrong namespace '%0'")
          << NamespaceNameInComment
          << FixItHint::CreateReplacement(
                 OldCommentRange, getNamespaceComment(ND, NeedLineBreak));
      return;
    }

    // This is not a recognized form of a namespace closing comment.
    // Leave line comment on the same line. Move block comment to the next line,
    // as it can be multi-line or there may be other tokens behind it.
    if (Comment.startswith("//"))
      NeedLineBreak = false;
  }

  diag(ND->getLocation(), "namespace not terminated with a closing comment")
      << FixItHint::CreateInsertion(AfterRBrace,
                                    std::string(SpacesBeforeComments, ' ') +
                                        getNamespaceComment(ND, NeedLineBreak));
}
Exemple #22
0
SourceRange getExpansionRange(SourceManager& sourceManager, const Decl* decl) {
    return SourceRange(getExpansionStart(sourceManager, decl),
            getExpansionEnd(sourceManager, decl));
}
void ProBoundsConstantArrayIndexCheck::check(
    const MatchFinder::MatchResult &Result) {
  const auto *Matched = Result.Nodes.getNodeAs<Expr>("expr");
  const auto *IndexExpr = Result.Nodes.getNodeAs<Expr>("index");

  if (IndexExpr->isValueDependent())
    return; // We check in the specialization.

  llvm::APSInt Index;
  if (!IndexExpr->isIntegerConstantExpr(Index, *Result.Context, nullptr,
                                        /*isEvaluated=*/true)) {
    SourceRange BaseRange;
    if (const auto *ArraySubscriptE = dyn_cast<ArraySubscriptExpr>(Matched))
      BaseRange = ArraySubscriptE->getBase()->getSourceRange();
    else
      BaseRange =
          dyn_cast<CXXOperatorCallExpr>(Matched)->getArg(0)->getSourceRange();
    SourceRange IndexRange = IndexExpr->getSourceRange();

    auto Diag = diag(Matched->getExprLoc(),
                     "do not use array subscript when the index is "
                     "not an integer constant expression; use gsl::at() "
                     "instead");
    if (!GslHeader.empty()) {
      Diag << FixItHint::CreateInsertion(BaseRange.getBegin(), "gsl::at(")
           << FixItHint::CreateReplacement(
                  SourceRange(BaseRange.getEnd().getLocWithOffset(1),
                              IndexRange.getBegin().getLocWithOffset(-1)),
                  ", ")
           << FixItHint::CreateReplacement(Matched->getLocEnd(), ")");

      Optional<FixItHint> Insertion = Inserter->CreateIncludeInsertion(
          Result.SourceManager->getMainFileID(), GslHeader,
          /*IsAngled=*/false);
      if (Insertion)
        Diag << Insertion.getValue();
    }
    return;
  }

  const auto *StdArrayDecl =
      Result.Nodes.getNodeAs<ClassTemplateSpecializationDecl>("type");

  // For static arrays, this is handled in clang-diagnostic-array-bounds.
  if (!StdArrayDecl)
    return;

  if (Index.isSigned() && Index.isNegative()) {
    diag(Matched->getExprLoc(),
         "std::array<> index %0 is negative")
        << Index.toString(10);
    return;
  }

  const TemplateArgumentList &TemplateArgs = StdArrayDecl->getTemplateArgs();
  if (TemplateArgs.size() < 2)
    return;
  // First template arg of std::array is the type, second arg is the size.
  const auto &SizeArg = TemplateArgs[1];
  if (SizeArg.getKind() != TemplateArgument::Integral)
    return;
  llvm::APInt ArraySize = SizeArg.getAsIntegral();

  // Get uint64_t values, because different bitwidths would lead to an assertion
  // in APInt::uge.
  if (Index.getZExtValue() >= ArraySize.getZExtValue()) {
    diag(Matched->getExprLoc(), "std::array<> index %0 is past the end of the array "
                                "(which contains %1 elements)")
        << Index.toString(10) << ArraySize.toString(10, false);
  }
}
std::vector<FixItHint> IncludeSorter::GetEdits() {
  if (SourceLocations.empty())
    return {};

  typedef std::map<int, std::pair<SourceRange, std::string>>
      FileLineToSourceEditMap;
  FileLineToSourceEditMap Edits;
  auto SourceLocationIterator = SourceLocations.begin();
  auto SourceLocationIteratorEnd = SourceLocations.end();

  // Compute the Edits that need to be done to each line to add, replace, or
  // delete inclusions.
  for (int IncludeKind = 0; IncludeKind < IK_InvalidInclude; ++IncludeKind) {
    std::sort(IncludeBucket[IncludeKind].begin(),
              IncludeBucket[IncludeKind].end());
    for (const auto &IncludeEntry : IncludeBucket[IncludeKind]) {
      auto &Location = IncludeLocations[IncludeEntry];
      SourceRangeVector::iterator LocationIterator = Location.begin();
      SourceRangeVector::iterator LocationIteratorEnd = Location.end();
      SourceRange FirstLocation = *LocationIterator;

      // If the first occurrence of a particular include is on the current
      // source line we are examining, leave it alone.
      if (FirstLocation == *SourceLocationIterator)
        ++LocationIterator;

      // Add the deletion Edits for any (remaining) instances of this inclusion,
      // and remove their Locations from the source Locations to be processed.
      for (; LocationIterator != LocationIteratorEnd; ++LocationIterator) {
        int LineNumber =
            SourceMgr->getSpellingLineNumber(LocationIterator->getBegin());
        Edits[LineNumber] = std::make_pair(*LocationIterator, "");
        SourceLocationIteratorEnd =
            std::remove(SourceLocationIterator, SourceLocationIteratorEnd,
                        *LocationIterator);
      }

      if (FirstLocation == *SourceLocationIterator) {
        // Do nothing except move to the next source Location (Location of an
        // inclusion in the original, unchanged source file).
        ++SourceLocationIterator;
        continue;
      }

      // Add (or append to) the replacement text for this line in source file.
      int LineNumber =
          SourceMgr->getSpellingLineNumber(SourceLocationIterator->getBegin());
      if (Edits.find(LineNumber) == Edits.end()) {
        Edits[LineNumber].first =
            SourceRange(SourceLocationIterator->getBegin());
      }
      StringRef SourceText = Lexer::getSourceText(
          CharSourceRange::getCharRange(FirstLocation), *SourceMgr, *LangOpts);
      Edits[LineNumber].second.append(SourceText.data(), SourceText.size());
    }

    // Clear the bucket.
    IncludeBucket[IncludeKind].clear();
  }

  // Go through the single-line Edits and combine them into blocks of Edits.
  int CurrentEndLine = 0;
  SourceRange CurrentRange;
  std::string CurrentText;
  std::vector<FixItHint> Fixes;
  for (const auto &LineEdit : Edits) {
    // If the current edit is on the next line after the previous edit, add it
    // to the current block edit.
    if (LineEdit.first == CurrentEndLine + 1 &&
        CurrentRange.getBegin() != CurrentRange.getEnd()) {
      SourceRange EditRange = LineEdit.second.first;
      if (EditRange.getBegin() != EditRange.getEnd()) {
        ++CurrentEndLine;
        CurrentRange.setEnd(EditRange.getEnd());
      }
      CurrentText += LineEdit.second.second;
      // Otherwise report the current block edit and start a new block.
    } else {
      if (CurrentEndLine) {
        Fixes.push_back(CreateFixIt(CurrentRange, CurrentText));
      }

      CurrentEndLine = LineEdit.first;
      CurrentRange = LineEdit.second.first;
      CurrentText = LineEdit.second.second;
    }
  }
  // Finally, report the current block edit if there is one.
  if (CurrentEndLine) {
    Fixes.push_back(CreateFixIt(CurrentRange, CurrentText));
  }

  // Reset the remaining internal state.
  SourceLocations.clear();
  IncludeLocations.clear();
  return Fixes;
}
Exemple #25
0
void Sema::actOnTParamCommandParamNameArg(TParamCommandComment *Command,
                                          SourceLocation ArgLocBegin,
                                          SourceLocation ArgLocEnd,
                                          StringRef Arg) {
  // Parser will not feed us more arguments than needed.
  assert(Command->getNumArgs() == 0);

  typedef BlockCommandComment::Argument Argument;
  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
                                                     ArgLocEnd),
                                         Arg);
  Command->setArgs(llvm::makeArrayRef(A, 1));

  if (!isTemplateOrSpecialization()) {
    // We already warned that this \\tparam is not attached to a template decl.
    return;
  }

  const TemplateParameterList *TemplateParameters =
      ThisDeclInfo->TemplateParameters;
  SmallVector<unsigned, 2> Position;
  if (resolveTParamReference(Arg, TemplateParameters, &Position)) {
    Command->setPosition(copyArray(llvm::makeArrayRef(Position)));
    llvm::StringMap<TParamCommandComment *>::iterator PrevCommandIt =
        TemplateParameterDocs.find(Arg);
    if (PrevCommandIt != TemplateParameterDocs.end()) {
      SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
      Diag(ArgLocBegin, diag::warn_doc_tparam_duplicate)
        << Arg << ArgRange;
      TParamCommandComment *PrevCommand = PrevCommandIt->second;
      Diag(PrevCommand->getLocation(), diag::note_doc_tparam_previous)
        << PrevCommand->getParamNameRange();
    }
    TemplateParameterDocs[Arg] = Command;
    return;
  }

  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
  Diag(ArgLocBegin, diag::warn_doc_tparam_not_found)
    << Arg << ArgRange;

  if (!TemplateParameters || TemplateParameters->size() == 0)
    return;

  StringRef CorrectedName;
  if (TemplateParameters->size() == 1) {
    const NamedDecl *Param = TemplateParameters->getParam(0);
    const IdentifierInfo *II = Param->getIdentifier();
    if (II)
      CorrectedName = II->getName();
  } else {
    CorrectedName = correctTypoInTParamReference(Arg, TemplateParameters);
  }

  if (!CorrectedName.empty()) {
    Diag(ArgLocBegin, diag::note_doc_tparam_name_suggestion)
      << CorrectedName
      << FixItHint::CreateReplacement(ArgRange, CorrectedName);
  }

  return;
}
bool MakeSmartPtrCheck::replaceNew(DiagnosticBuilder &Diag,
                                   const CXXNewExpr *New,
                                   SourceManager& SM) {
  SourceLocation NewStart = New->getSourceRange().getBegin();
  SourceLocation NewEnd = New->getSourceRange().getEnd();

  // Skip when the source location of the new expression is invalid.
  if (NewStart.isInvalid() || NewEnd.isInvalid())
    return false;

  std::string ArraySizeExpr;
  if (const auto* ArraySize = New->getArraySize()) {
    ArraySizeExpr = Lexer::getSourceText(CharSourceRange::getTokenRange(
                                             ArraySize->getSourceRange()),
                                         SM, getLangOpts())
                        .str();
  }

  switch (New->getInitializationStyle()) {
  case CXXNewExpr::NoInit: {
    if (ArraySizeExpr.empty()) {
      Diag << FixItHint::CreateRemoval(SourceRange(NewStart, NewEnd));
    } else {
      // New array expression without written initializer:
      //   smart_ptr<Foo[]>(new Foo[5]);
      Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
                                           ArraySizeExpr);
    }
    break;
  }
  case CXXNewExpr::CallInit: {
    // FIXME: Add fixes for constructors with parameters that can be created
    // with a C++11 braced-init-list (e.g. std::vector, std::map).
    // Unlike ordinal cases, braced list can not be deduced in
    // std::make_smart_ptr, we need to specify the type explicitly in the fixes:
    //   struct S { S(std::initializer_list<int>, int); };
    //   struct S2 { S2(std::vector<int>); };
    //   smart_ptr<S>(new S({1, 2, 3}, 1));  // C++98 call-style initialization
    //   smart_ptr<S>(new S({}, 1));
    //   smart_ptr<S2>(new S2({1})); // implicit conversion:
    //                               //   std::initializer_list => std::vector
    // The above samples have to be replaced with:
    //   std::make_smart_ptr<S>(std::initializer_list<int>({1, 2, 3}), 1);
    //   std::make_smart_ptr<S>(std::initializer_list<int>({}), 1);
    //   std::make_smart_ptr<S2>(std::vector<int>({1}));
    if (const auto *CE = New->getConstructExpr()) {
      for (const auto *Arg : CE->arguments()) {
        if (isa<CXXStdInitializerListExpr>(Arg)) {
          return false;
        }
        // Check whether we construct a class from a std::initializer_list.
        // If so, we won't generate the fixes.
        auto IsStdInitListInitConstructExpr = [](const Expr* E) {
          assert(E);
          if (const auto *ImplicitCE = dyn_cast<CXXConstructExpr>(E)) {
            if (ImplicitCE->isStdInitListInitialization())
              return true;
          }
          return false;
        };
        if (IsStdInitListInitConstructExpr(Arg->IgnoreImplicit()))
          return false;
      }
    }
    if (ArraySizeExpr.empty()) {
      SourceRange InitRange = New->getDirectInitRange();
      Diag << FixItHint::CreateRemoval(
          SourceRange(NewStart, InitRange.getBegin()));
      Diag << FixItHint::CreateRemoval(SourceRange(InitRange.getEnd(), NewEnd));
    }
    else {
      // New array expression with default/value initialization:
      //   smart_ptr<Foo[]>(new int[5]());
      //   smart_ptr<Foo[]>(new Foo[5]());
      Diag << FixItHint::CreateReplacement(SourceRange(NewStart, NewEnd),
                                           ArraySizeExpr);
    }
    break;
  }
  case CXXNewExpr::ListInit: {
    // Range of the substring that we do not want to remove.
    SourceRange InitRange;
    if (const auto *NewConstruct = New->getConstructExpr()) {
      if (NewConstruct->isStdInitListInitialization()) {
        // FIXME: Add fixes for direct initialization with the initializer-list
        // constructor. Similar to the above CallInit case, the type has to be
        // specified explicitly in the fixes.
        //   struct S { S(std::initializer_list<int>); };
        //   smart_ptr<S>(new S{1, 2, 3});  // C++11 direct list-initialization
        //   smart_ptr<S>(new S{});  // use initializer-list consturctor
        // The above cases have to be replaced with:
        //   std::make_smart_ptr<S>(std::initializer_list<int>({1, 2, 3}));
        //   std::make_smart_ptr<S>(std::initializer_list<int>({}));
        return false;
      } else {
        // Direct initialization with ordinary constructors.
        //   struct S { S(int x); S(); };
        //   smart_ptr<S>(new S{5});
        //   smart_ptr<S>(new S{}); // use default constructor
        // The arguments in the initialization list are going to be forwarded to
        // the constructor, so this has to be replaced with:
        //   std::make_smart_ptr<S>(5);
        //   std::make_smart_ptr<S>();
        InitRange = SourceRange(
            NewConstruct->getParenOrBraceRange().getBegin().getLocWithOffset(1),
            NewConstruct->getParenOrBraceRange().getEnd().getLocWithOffset(-1));
      }
    } else {
      // Aggregate initialization.
      //   smart_ptr<Pair>(new Pair{first, second});
      // Has to be replaced with:
      //   smart_ptr<Pair>(Pair{first, second});
      InitRange = SourceRange(
          New->getAllocatedTypeSourceInfo()->getTypeLoc().getLocStart(),
          New->getInitializer()->getSourceRange().getEnd());
    }
    Diag << FixItHint::CreateRemoval(
        CharSourceRange::getCharRange(NewStart, InitRange.getBegin()));
    Diag << FixItHint::CreateRemoval(
        SourceRange(InitRange.getEnd().getLocWithOffset(1), NewEnd));
    break;
  }
  }
  return true;
}
SourceRange TranslationUnit::sourceRange(uint fromLine, uint fromColumn, uint toLine, uint toColumn) const
{
    return SourceRange(sourceLocationAt(fromLine, fromColumn),
                       sourceLocationAt(toLine, toColumn));
}
// ECMA 15.3.2 The Function Constructor
JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
{
    UString p("");
    UString body;
    int argsSize = args.size();
    if (argsSize == 0)
        body = "";
    else if (argsSize == 1)
        body = args[0]->toString(exec);
    else {
        p = args[0]->toString(exec);
        for (int k = 1; k < argsSize - 1; k++)
            p += "," + args[k]->toString(exec);
        body = args[argsSize - 1]->toString(exec);
    }

    // parse the source code
    int sourceId;
    int errLine;
    UString errMsg;
    RefPtr<SourceProvider> source = UStringSourceProvider::create(body);
    RefPtr<FunctionBodyNode> functionBody = exec->parser()->parse<FunctionBodyNode>(exec, sourceURL, lineNumber, source, &sourceId, &errLine, &errMsg);

    // No program node == syntax error - throw a syntax error
    if (!functionBody)
        // We can't return a Completion(Throw) here, so just set the exception
        // and return it
        return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL);
    
    functionBody->setSource(SourceRange(source, 0, source->length()));
    ScopeChain scopeChain(exec->lexicalGlobalObject(), exec->globalThisValue());

    JSFunction* function = new (exec) JSFunction(exec, functionName, functionBody.get(), scopeChain.node());

    // parse parameter list. throw syntax error on illegal identifiers
    int len = p.size();
    const UChar* c = p.data();
    int i = 0, params = 0;
    UString param;
    while (i < len) {
        while (*c == ' ' && i < len)
            c++, i++;
        if (Lexer::isIdentStart(c[0])) {  // else error
            param = UString(c, 1);
            c++, i++;
            while (i < len && (Lexer::isIdentPart(c[0]))) {
                param.append(*c);
                c++, i++;
            }
            while (i < len && *c == ' ')
                c++, i++;
            if (i == len) {
                functionBody->parameters().append(Identifier(exec, param));
                params++;
                break;
            } else if (*c == ',') {
                functionBody->parameters().append(Identifier(exec, param));
                params++;
                c++, i++;
                continue;
            } // else error
        }
        return throwError(exec, SyntaxError, "Syntax error in parameter list");
    }
  
    JSObject* prototype = constructEmptyObject(exec);
    prototype->putDirect(exec->propertyNames().constructor, function, DontEnum);
    function->putDirect(exec->propertyNames().prototype, prototype, DontDelete);
    return function;
}
Exemple #29
0
void Sema::actOnParamCommandParamNameArg(ParamCommandComment *Command,
                                         SourceLocation ArgLocBegin,
                                         SourceLocation ArgLocEnd,
                                         StringRef Arg) {
  // Parser will not feed us more arguments than needed.
  assert(Command->getNumArgs() == 0);

  if (!Command->isDirectionExplicit()) {
    // User didn't provide a direction argument.
    Command->setDirection(ParamCommandComment::In, /* Explicit = */ false);
  }
  typedef BlockCommandComment::Argument Argument;
  Argument *A = new (Allocator) Argument(SourceRange(ArgLocBegin,
                                                     ArgLocEnd),
                                         Arg);
  Command->setArgs(llvm::makeArrayRef(A, 1));

  if (!isFunctionDecl()) {
    // We already warned that this \\param is not attached to a function decl.
    return;
  }

  ArrayRef<const ParmVarDecl *> ParamVars = getParamVars();

  // Check that referenced parameter name is in the function decl.
  const unsigned ResolvedParamIndex = resolveParmVarReference(Arg, ParamVars);
  if (ResolvedParamIndex != ParamCommandComment::InvalidParamIndex) {
    Command->setParamIndex(ResolvedParamIndex);
    if (ParamVarDocs[ResolvedParamIndex]) {
      SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
      Diag(ArgLocBegin, diag::warn_doc_param_duplicate)
        << Arg << ArgRange;
      ParamCommandComment *PrevCommand = ParamVarDocs[ResolvedParamIndex];
      Diag(PrevCommand->getLocation(), diag::note_doc_param_previous)
        << PrevCommand->getParamNameRange();
    }
    ParamVarDocs[ResolvedParamIndex] = Command;
    return;
  }

  SourceRange ArgRange(ArgLocBegin, ArgLocEnd);
  Diag(ArgLocBegin, diag::warn_doc_param_not_found)
    << Arg << ArgRange;

  // No parameters -- can't suggest a correction.
  if (ParamVars.size() == 0)
    return;

  unsigned CorrectedParamIndex = ParamCommandComment::InvalidParamIndex;
  if (ParamVars.size() == 1) {
    // If function has only one parameter then only that parameter
    // can be documented.
    CorrectedParamIndex = 0;
  } else {
    // Do typo correction.
    CorrectedParamIndex = correctTypoInParmVarReference(Arg, ParamVars);
  }
  if (CorrectedParamIndex != ParamCommandComment::InvalidParamIndex) {
    const ParmVarDecl *CorrectedPVD = ParamVars[CorrectedParamIndex];
    if (const IdentifierInfo *CorrectedII = CorrectedPVD->getIdentifier())
      Diag(ArgLocBegin, diag::note_doc_param_name_suggestion)
        << CorrectedII->getName()
        << FixItHint::CreateReplacement(ArgRange, CorrectedII->getName());
  }

  return;
}
void OMPPragmaHandler::HandlePragma(Preprocessor &PP,
                                    PragmaIntroducerKind Introducer,
                                    SourceRange IntroducerRange,
                                    Token &FirstTok) {


  Diags.Report(IntroducerRange.getBegin(), DiagFoundPragmaStmt);
                                    
  // TODO: Clean this up because I'm too lazy to now
  PragmaDirective * DirectivePointer = new PragmaDirective;
  PragmaDirective &Directive = *DirectivePointer;
    
  // First lex the pragma statement extracting the variable names

  SourceLocation Loc = IntroducerRange.getBegin();
  Token Tok = FirstTok;
  StringRef ident = getIdentifier(Tok);
  
  if (ident != "omp") {
    LexUntil(PP, Tok, clang::tok::eod);
    return;
  }
    
  PP.Lex(Tok);
  ident = getIdentifier(Tok);
  
  bool isParallel = false;
  bool isThreadPrivate = false;

  if (ident == "parallel") {

    PragmaConstruct C;
    C.Type = ParallelConstruct;
    C.Range = getTokenRange(Tok, PP);
    Directive.insertConstruct(C);
    isParallel = true;

  } else if (ident == "sections"
             || ident == "section"
             || ident == "task"
             || ident == "taskyield"
             || ident == "taskwait"
             || ident == "atomic"
             || ident == "ordered") {

    Diags.Report(Tok.getLocation(), DiagUnsupportedConstruct);

    LexUntil(PP, Tok, clang::tok::eod);
    return;

  } else if (ident == "for") {

    PragmaConstruct C;
    C.Type = ForConstruct;
    C.Range = getTokenRange(Tok, PP);
    Directive.insertConstruct(C);

  } else if (ident == "threadprivate") {
  
    isThreadPrivate = true;

    PragmaConstruct C;
    C.Type = ThreadprivateConstruct;
    C.Range = getTokenRange(Tok, PP);
    Directive.insertConstruct(C);
  
  } else if (ident == "single") {

    PragmaConstruct C;
    C.Type = SingleConstruct;
    C.Range = getTokenRange(Tok, PP);
    Directive.insertConstruct(C);

  } else if (ident == "master") {

    PragmaConstruct C;
    C.Type = MasterConstruct;
    C.Range = getTokenRange(Tok, PP);
    Directive.insertConstruct(C);

  } else if (ident == "critical"
             || ident == "flush") {

    // Ignored Directive
    // (Critical, Flush)
    LexUntil(PP, Tok, clang::tok::eod);
    return;
  
  } else if (ident == "barrier") {

    PragmaConstruct C;
    C.Type = BarrierConstruct;
    C.Range = getTokenRange(Tok, PP);
    Directive.insertConstruct(C);

  } else {
    
    Diags.Report(Tok.getLocation(), DiagUnknownDirective);
    return;
    
  }
  
  if (!isThreadPrivate) {
    PP.Lex(Tok);
  }

  if (isParallel) {

    ident = getIdentifier(Tok);
    
    if (ident == "sections") {

      Diags.Report(Tok.getLocation(), DiagUnsupportedConstruct);

      LexUntil(PP, Tok, clang::tok::eod);
      return;

    } else if (ident == "for") {

      PragmaConstruct C;
      C.Type = ForConstruct;
      C.Range = getTokenRange(Tok, PP);
      Directive.insertConstruct(C);
    
      PP.Lex(Tok);
      
    } else {

      // Just a standard "#pragma omp parallel" clause
      if (Tok.isNot(clang::tok::eod)
             && PragmaDirective::getClauseType(ident)
                == UnknownClause) {
       
        Diags.Report(Tok.getLocation(), DiagUnknownClause);
        return;
                
      }

    }
  
  }
  
  // If we've made it this far then we either have:
  // "#pragma omp parallel",
  // "#pragma omp parallel for",
  // "#pragma omp for",
  // "#pragma omp threadprivate
  
  // Need to read in the options, if they exists
  // Don't really care about them unless there exists a private(...) list
  // In which case, get the variables inside that list
  // But we read them all in anyway.

  // There's also threadprivate, which won't have any clauses, but will have
  // a list of private variables just after the threadprivate directive
  // Treating threadprivate as a clause and directive at the same time.
  
  while(Tok.isNot(clang::tok::eod)) {
  
    PragmaClause C;

    ident = getIdentifier(Tok);
    C.Type = PragmaDirective::getClauseType(ident);

    if (C.Type == UnknownClause) {
     
      Diags.Report(Tok.getLocation(), DiagUnknownClause);
      return;
              
    }

    SourceLocation clauseStart = Tok.getLocation();
    SourceLocation clauseEnd = PP.getLocForEndOfToken(clauseStart);

    PP.Lex(Tok);
      
    if (Tok.is(clang::tok::l_paren)) {

      if (!handleList(Tok, PP, C)) {
  
        Diags.Report(clauseStart, DiagMalformedStatement);

        LexUntil(PP, Tok, clang::tok::eod);
        return;
      }
      
      clauseEnd = PP.getLocForEndOfToken(Tok.getLocation());

      // Eat the clang::tok::r_paren
      PP.Lex(Tok);

    }
    
    C.Range = SourceRange(clauseStart, clauseEnd);
    
    Directive.insertClause(C);

  }
  
  SourceLocation EndLoc = PP.getLocForEndOfToken(Tok.getLocation());

  Directive.setRange(SourceRange(Loc, EndLoc));

  Directives.insert(std::make_pair(Loc.getRawEncoding(), DirectivePointer));

  // Then replace with parseable compound statement to catch in Sema, and 
  // references to private variables;
  // {
  //   i;
  //   j;
  //   k;
  // }
  
  // If it's a threadprivate directive, then we skip this completely
  if (isThreadPrivate) {
    return;
  }
  
  set<IdentifierInfo *> PrivateVars = Directive.getPrivateIdentifiers();

  int tokenCount = 2 + 2 * PrivateVars.size();
  int currentToken = 0;    
  
  Token * Toks = new Token[tokenCount];

  Toks[currentToken++] = createToken(Loc, clang::tok::l_brace);

  set<IdentifierInfo *>::iterator PrivIt;
  for (PrivIt = PrivateVars.begin(); PrivIt != PrivateVars.end(); PrivIt++) {
  
    Toks[currentToken++] = createToken(Loc, clang::tok::identifier, *PrivIt);
    Toks[currentToken++] = createToken(Loc, clang::tok::semi);

  }

  Toks[currentToken++] = createToken(EndLoc, clang::tok::r_brace);

  assert(currentToken == tokenCount);
  
  Diags.setDiagnosticGroupMapping("unused-value", 
                                  clang::diag::MAP_IGNORE,
                                  Loc);

  Diags.setDiagnosticGroupMapping("unused-value", 
                                  clang::diag::MAP_WARNING,
                                  EndLoc);

  PP.EnterTokenStream(Toks, tokenCount, true, true);
  
}