bool PragmaCommentHandler::HandleComment(Preprocessor &PP, SourceRange Range) { StringRef Text = Lexer::getSourceText(CharSourceRange::getCharRange(Range), PP.getSourceManager(), PP.getLangOpts()); size_t Pos = Text.find(IWYUPragma); if (Pos == StringRef::npos) return false; StringRef RemappingFilePath = Text.substr(Pos + std::strlen(IWYUPragma)); Collector->addHeaderMapping( PP.getSourceManager().getFilename(Range.getBegin()), RemappingFilePath.trim("\"<>")); return false; }
bool HandleComment(Preprocessor &PP, SourceRange Range) override { StringRef Text = Lexer::getSourceText(CharSourceRange::getCharRange(Range), PP.getSourceManager(), PP.getLangOpts()); if (!Text.consume_front(IWYUPragma)) return false; // FIXME(ioeric): resolve the header and store actual file path. For now, // we simply assume the written header is suitable to be #included. Includes->addMapping(PP.getSourceManager().getFilename(Range.getBegin()), isLiteralInclude(Text) ? Text.str() : ("\"" + Text + "\"").str()); return false; }
/// Returns true if the statement is expanded from a configuration macro. static bool isExpandedFromConfigurationMacro(const Stmt *S, Preprocessor &PP, bool IgnoreYES_NO = false) { // FIXME: This is not very precise. Here we just check to see if the // value comes from a macro, but we can do much better. This is likely // to be over conservative. This logic is factored into a separate function // so that we can refine it later. SourceLocation L = S->getBeginLoc(); if (L.isMacroID()) { SourceManager &SM = PP.getSourceManager(); if (IgnoreYES_NO) { // The Objective-C constant 'YES' and 'NO' // are defined as macros. Do not treat them // as configuration values. SourceLocation TopL = getTopMostMacro(L, SM); StringRef MacroName = PP.getImmediateMacroName(TopL); if (MacroName == "YES" || MacroName == "NO") return false; } else if (!PP.getLangOpts().CPlusPlus) { // Do not treat C 'false' and 'true' macros as configuration values. SourceLocation TopL = getTopMostMacro(L, SM); StringRef MacroName = PP.getImmediateMacroName(TopL); if (MacroName == "false" || MacroName == "true") return false; } return true; } return false; }
/// Initializes an InclusionRewriter with a \p PP source and \p OS destination. InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers, bool UseLineDirectives) : PP(PP), SM(PP.getSourceManager()), OS(OS), MainEOL("\n"), PredefinesBuffer(nullptr), ShowLineMarkers(ShowLineMarkers), UseLineDirectives(UseLineDirectives), LastInclusionLocation(SourceLocation()) {}
/// InclusionRewriterInInput - Implement -frewrite-includes mode. void clang::RewriteIncludesInInput(Preprocessor &PP, raw_ostream *OS, const PreprocessorOutputOptions &Opts) { SourceManager &SM = PP.getSourceManager(); InclusionRewriter *Rewrite = new InclusionRewriter(PP, *OS, Opts.ShowLineMarkers); PP.addPPCallbacks(Rewrite); PP.IgnorePragmas(); // First let the preprocessor process the entire file and call callbacks. // Callbacks will record which #include's were actually performed. PP.EnterMainSourceFile(); Token Tok; // Only preprocessor directives matter here, so disable macro expansion // everywhere else as an optimization. // TODO: It would be even faster if the preprocessor could be switched // to a mode where it would parse only preprocessor directives and comments, // nothing else matters for parsing or processing. PP.SetMacroExpansionOnlyInDirectives(); do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); Rewrite->setPredefinesBuffer(SM.getBuffer(PP.getPredefinesFileID())); Rewrite->Process(PP.getPredefinesFileID(), SrcMgr::C_User); Rewrite->Process(SM.getMainFileID(), SrcMgr::C_User); OS->flush(); }
/// LexRawTokensFromMainFile - Lets all the raw tokens from the main file into /// the specified vector. static void LexRawTokensFromMainFile(Preprocessor &PP, std::vector<Token> &RawTokens) { SourceManager &SM = PP.getSourceManager(); // Create a lexer to lex all the tokens of the main file in raw mode. Even // though it is in raw mode, it will not return comments. const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOpts()); // Switch on comment lexing because we really do want them. RawLex.SetCommentRetentionState(true); Token RawTok; do { RawLex.LexFromRawLexer(RawTok); // If we have an identifier with no identifier info for our raw token, look // up the indentifier info. This is important for equality comparison of // identifier tokens. if (RawTok.is(tok::raw_identifier)) PP.LookUpIdentifierInfo(RawTok); RawTokens.push_back(RawTok); } while (RawTok.isNot(tok::eof)); }
void clang::CacheTokens(Preprocessor &PP, llvm::raw_fd_ostream* OS) { // Get the name of the main file. const SourceManager &SrcMgr = PP.getSourceManager(); const FileEntry *MainFile = SrcMgr.getFileEntryForID(SrcMgr.getMainFileID()); SmallString<128> MainFilePath(MainFile->getName()); llvm::sys::fs::make_absolute(MainFilePath); // Create the PTHWriter. PTHWriter PW(*OS, PP); // Install the 'stat' system call listener in the FileManager. StatListener *StatCache = new StatListener(PW.getPM()); PP.getFileManager().addStatCache(StatCache, /*AtBeginning=*/true); // Lex through the entire file. This will populate SourceManager with // all of the header information. Token Tok; PP.EnterMainSourceFile(); do { PP.Lex(Tok); } while (Tok.isNot(tok::eof)); // Generate the PTH file. PP.getFileManager().removeStatCache(StatCache); PW.GeneratePTH(MainFilePath.str()); }
/// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// void clang::InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &InitOpts, const HeaderSearchOptions &HSOpts) { std::vector<char> PredefineBuffer; InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), PP.getFileManager(), InitOpts); const char *LineDirective = "# 1 \"<built-in>\" 3\n"; PredefineBuffer.insert(PredefineBuffer.end(), LineDirective, LineDirective+strlen(LineDirective)); // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) InitializePredefinedMacros(PP.getTargetInfo(), PP.getLangOptions(), PredefineBuffer); // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. LineDirective = "# 1 \"<command line>\" 1\n"; PredefineBuffer.insert(PredefineBuffer.end(), LineDirective, LineDirective+strlen(LineDirective)); // Process #define's and #undef's in the order they are given. for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { if (InitOpts.Macros[i].second) // isUndef UndefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str()); else DefineBuiltinMacro(PredefineBuffer, InitOpts.Macros[i].first.c_str(), &PP.getDiagnostics()); } // If -imacros are specified, include them now. These are processed before // any -include directives. for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i) AddImplicitIncludeMacros(PredefineBuffer, InitOpts.MacroIncludes[i]); // Process -include directives. for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) { const std::string &Path = InitOpts.Includes[i]; if (Path == InitOpts.ImplicitPTHInclude) AddImplicitIncludePTH(PredefineBuffer, PP, Path); else AddImplicitInclude(PredefineBuffer, Path); } // Exit the command line and go back to <built-in> (2 is LC_LEAVE). LineDirective = "# 1 \"<built-in>\" 2\n"; PredefineBuffer.insert(PredefineBuffer.end(), LineDirective, LineDirective+strlen(LineDirective)); // Null terminate PredefinedBuffer and add it. PredefineBuffer.push_back(0); PP.setPredefines(&PredefineBuffer[0]); // Initialize the header search object. ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, PP.getLangOptions(), PP.getTargetInfo().getTriple()); }
/// FindExpectedDiags - Lex the main source file to find all of the // expected errors and warnings. static void FindExpectedDiags(Preprocessor &PP, ExpectedData &ED) { // Create a raw lexer to pull all the comments out of the main file. We don't // want to look in #include'd headers for expected-error strings. SourceManager &SM = PP.getSourceManager(); FileID FID = SM.getMainFileID(); if (SM.getMainFileID().isInvalid()) return; // Create a lexer to lex all the tokens of the main file in raw mode. const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); Lexer RawLex(FID, FromFile, SM, PP.getLangOptions()); // Return comments as tokens, this is how we find expected diagnostics. RawLex.SetCommentRetentionState(true); Token Tok; Tok.setKind(tok::comment); while (Tok.isNot(tok::eof)) { RawLex.Lex(Tok); if (!Tok.is(tok::comment)) continue; std::string Comment = PP.getSpelling(Tok); if (Comment.empty()) continue; // Find all expected errors/warnings/notes. ParseDirective(&Comment[0], Comment.size(), ED, PP, Tok.getLocation()); }; }
/// Initializes an InclusionRewriter with a \p PP source and \p OS destination. InclusionRewriter::InclusionRewriter(Preprocessor &PP, raw_ostream &OS, bool ShowLineMarkers) : PP(PP), SM(PP.getSourceManager()), OS(OS), ShowLineMarkers(ShowLineMarkers), LastInsertedFileChange(FileChanges.end()) { // If we're in microsoft mode, use normal #line instead of line markers. UseLineDirective = PP.getLangOpts().MicrosoftExt; }
/// HandleComment - Hook into the preprocessor and extract comments containing /// expected errors and warnings. bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, SourceRange Comment) { SourceManager &SM = PP.getSourceManager(); // If this comment is for a different source manager, ignore it. if (SrcManager && &SM != SrcManager) return false; SourceLocation CommentBegin = Comment.getBegin(); const char *CommentRaw = SM.getCharacterData(CommentBegin); StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw); if (C.empty()) return false; // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { ParseDirective(C, &ED, SM, &PP, CommentBegin, Status, *Markers); return false; } std::string C2; C2.reserve(C.size()); for (size_t last = 0;; loc = C.find('\\', last)) { if (loc == StringRef::npos || loc == C.size()) { C2 += C.substr(last); break; } C2 += C.substr(last, loc-last); last = loc + 1; if (C[last] == '\n' || C[last] == '\r') { ++last; // Escape \r\n or \n\r, but not \n\n. if (last < C.size()) if (C[last] == '\n' || C[last] == '\r') if (C[last] != C[last-1]) ++last; } else { // This was just a normal backslash. C2 += '\\'; } } if (!C2.empty()) ParseDirective(C2, &ED, SM, &PP, CommentBegin, Status, *Markers); return false; }
/// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// void mlang::InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &InitOpts, const ImportSearchOptions &HSOpts, const FrontendOptions &FEOpts) { InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), PP.getFileManager(), InitOpts); // Initialize the import search object. // ApplyImportSearchOptions(PP.getImportSearchInfo(), HSOpts, // PP.getLangOptions(), // PP.getTargetInfo().getTriple()); }
static void emitPremigrationErrors(const CapturedDiagList &arcDiags, const DiagnosticOptions &diagOpts, Preprocessor &PP) { TextDiagnosticPrinter printer(llvm::errs(), diagOpts); IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs()); IntrusiveRefCntPtr<DiagnosticsEngine> Diags( new DiagnosticsEngine(DiagID, &printer, /*ShouldOwnClient=*/false)); Diags->setSourceManager(&PP.getSourceManager()); printer.BeginSourceFile(PP.getLangOpts(), &PP); arcDiags.reportDiagnostics(*Diags); printer.EndSourceFile(); }
/// HandleComment - Hook into the preprocessor and extract comments containing /// expected errors and warnings. bool VerifyDiagnosticConsumer::HandleComment(Preprocessor &PP, SourceRange Comment) { SourceManager &SM = PP.getSourceManager(); SourceLocation CommentBegin = Comment.getBegin(); const char *CommentRaw = SM.getCharacterData(CommentBegin); StringRef C(CommentRaw, SM.getCharacterData(Comment.getEnd()) - CommentRaw); if (C.empty()) return false; // Fold any "\<EOL>" sequences size_t loc = C.find('\\'); if (loc == StringRef::npos) { if (ParseDirective(C, ED, SM, CommentBegin, PP.getDiagnostics())) if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin))) FilesWithDirectives.insert(E); return false; } std::string C2; C2.reserve(C.size()); for (size_t last = 0;; loc = C.find('\\', last)) { if (loc == StringRef::npos || loc == C.size()) { C2 += C.substr(last); break; } C2 += C.substr(last, loc-last); last = loc + 1; if (C[last] == '\n' || C[last] == '\r') { ++last; // Escape \r\n or \n\r, but not \n\n. if (last < C.size()) if (C[last] == '\n' || C[last] == '\r') if (C[last] != C[last-1]) ++last; } else { // This was just a normal backslash. C2 += '\\'; } } if (!C2.empty()) if (ParseDirective(C2, ED, SM, CommentBegin, PP.getDiagnostics())) if (const FileEntry *E = SM.getFileEntryForID(SM.getFileID(CommentBegin))) FilesWithDirectives.insert(E); return false; }
/// FindExpectedDiags - Lex the main source file to find all of the // expected errors and warnings. static void FindExpectedDiags(Preprocessor &PP, DiagList &ExpectedErrors, DiagList &ExpectedWarnings, DiagList &ExpectedNotes) { // Create a raw lexer to pull all the comments out of the main file. We don't // want to look in #include'd headers for expected-error strings. FileID FID = PP.getSourceManager().getMainFileID(); // Create a lexer to lex all the tokens of the main file in raw mode. Lexer RawLex(FID, PP.getSourceManager(), PP.getLangOptions()); // Return comments as tokens, this is how we find expected diagnostics. RawLex.SetCommentRetentionState(true); Token Tok; Tok.setKind(tok::comment); while (Tok.isNot(tok::eof)) { RawLex.Lex(Tok); if (!Tok.is(tok::comment)) continue; std::string Comment = PP.getSpelling(Tok); if (Comment.empty()) continue; // Find all expected errors. FindDiagnostics(&Comment[0], Comment.size(), ExpectedErrors, PP, Tok.getLocation(), "expected-error"); // Find all expected warnings. FindDiagnostics(&Comment[0], Comment.size(), ExpectedWarnings, PP, Tok.getLocation(), "expected-warning"); // Find all expected notes. FindDiagnostics(&Comment[0], Comment.size(), ExpectedNotes, PP, Tok.getLocation(), "expected-note"); }; }
/// CheckResults - This compares the expected results to those that /// were actually reported. It emits any discrepencies. Return "true" if there /// were problems. Return "false" otherwise. /// static bool CheckResults(Preprocessor &PP, const DiagList &ExpectedErrors, const DiagList &ExpectedWarnings, const DiagList &ExpectedNotes) { const DiagnosticClient *DiagClient = PP.getDiagnostics().getClient(); assert(DiagClient != 0 && "DiagChecker requires a valid TextDiagnosticBuffer"); const TextDiagnosticBuffer &Diags = static_cast<const TextDiagnosticBuffer&>(*DiagClient); SourceManager &SourceMgr = PP.getSourceManager(); // We want to capture the delta between what was expected and what was // seen. // // Expected \ Seen - set expected but not seen // Seen \ Expected - set seen but not expected bool HadProblem = false; // See if there are error mismatches. HadProblem |= CompareDiagLists(SourceMgr, ExpectedErrors.begin(), ExpectedErrors.end(), Diags.err_begin(), Diags.err_end(), "Errors expected but not seen:", "Errors seen but not expected:"); // See if there are warning mismatches. HadProblem |= CompareDiagLists(SourceMgr, ExpectedWarnings.begin(), ExpectedWarnings.end(), Diags.warn_begin(), Diags.warn_end(), "Warnings expected but not seen:", "Warnings seen but not expected:"); // See if there are note mismatches. HadProblem |= CompareDiagLists(SourceMgr, ExpectedNotes.begin(), ExpectedNotes.end(), Diags.note_begin(), Diags.note_end(), "Notes expected but not seen:", "Notes seen but not expected:"); return HadProblem; }
/// GetFirstChar - Get the first character of the token \arg Tok, /// avoiding calls to getSpelling where possible. static char GetFirstChar(Preprocessor &PP, const Token &Tok) { if (IdentifierInfo *II = Tok.getIdentifierInfo()) { // Avoid spelling identifiers, the most common form of token. return II->getName()[0]; } else if (!Tok.needsCleaning()) { if (Tok.isLiteral() && Tok.getLiteralData()) { return *Tok.getLiteralData(); } else { SourceManager &SM = PP.getSourceManager(); return *SM.getCharacterData(SM.getSpellingLoc(Tok.getLocation())); } } else if (Tok.getLength() < 256) { char Buffer[256]; const char *TokPtr = Buffer; PP.getSpelling(Tok, TokPtr); return TokPtr[0]; } else { return PP.getSpelling(Tok)[0]; } }
void clang::DoRewriteTest(Preprocessor &PP, raw_ostream* OS) { SourceManager &SM = PP.getSourceManager(); const LangOptions &LangOpts = PP.getLangOptions(); TokenRewriter Rewriter(SM.getMainFileID(), SM, LangOpts); // Throw <i> </i> tags around comments. for (TokenRewriter::token_iterator I = Rewriter.token_begin(), E = Rewriter.token_end(); I != E; ++I) { if (I->isNot(tok::comment)) continue; Rewriter.AddTokenBefore(I, "<i>"); Rewriter.AddTokenAfter(I, "</i>"); } // Print out the output. for (TokenRewriter::token_iterator I = Rewriter.token_begin(), E = Rewriter.token_end(); I != E; ++I) *OS << PP.getSpelling(*I); }
bool HandleComment(Preprocessor &PP, SourceRange Range) override { StringRef Text = Lexer::getSourceText(CharSourceRange::getCharRange(Range), PP.getSourceManager(), PP.getLangOpts()); SmallVector<StringRef, 4> Matches; if (!TodoMatch.match(Text, &Matches)) return false; StringRef Username = Matches[1]; StringRef Comment = Matches[3]; if (!Username.empty()) return false; std::string NewText = ("// TODO(" + Twine(User) + "): " + Comment).str(); Check.diag(Range.getBegin(), "missing username/bug in TODO") << FixItHint::CreateReplacement(CharSourceRange::getCharRange(Range), NewText); return false; }
/// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // Check the type specifier components first. SourceManager &SrcMgr = PP.getSourceManager(); // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType); // signed double -> double. TypeSpecSign = TSS_unspecified; } } // Validate the width of the type. switch (TypeSpecWidth) { case TSW_unspecified: break; case TSW_short: // short int case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { Diag(D, TSWLoc, SrcMgr, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) << CodeModificationHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecComplex = TSC_unspecified; } } // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && getStorageClassSpec()) { DeclSpec::SCS SC = getStorageClassSpec(); const char *SpecName = getSpecifierName(SC); SourceLocation SCLoc = getStorageClassSpecLoc(); SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) << SpecName << CodeModificationHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); ClearStorageClassSpecs(); } // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? }
/// RewriteMacrosInInput - Implement -rewrite-macros mode. void clang::RewriteMacrosInInput(Preprocessor &PP, raw_ostream *OS) { SourceManager &SM = PP.getSourceManager(); Rewriter Rewrite; Rewrite.setSourceMgr(SM, PP.getLangOpts()); RewriteBuffer &RB = Rewrite.getEditBuffer(SM.getMainFileID()); std::vector<Token> RawTokens; LexRawTokensFromMainFile(PP, RawTokens); unsigned CurRawTok = 0; Token RawTok = GetNextRawTok(RawTokens, CurRawTok, false); // Get the first preprocessing token. PP.EnterMainSourceFile(); Token PPTok; PP.Lex(PPTok); // Preprocess the input file in parallel with raw lexing the main file. Ignore // all tokens that are preprocessed from a file other than the main file (e.g. // a header). If we see tokens that are in the preprocessed file but not the // lexed file, we have a macro expansion. If we see tokens in the lexed file // that aren't in the preprocessed view, we have macros that expand to no // tokens, or macro arguments etc. while (RawTok.isNot(tok::eof) || PPTok.isNot(tok::eof)) { SourceLocation PPLoc = SM.getExpansionLoc(PPTok.getLocation()); // If PPTok is from a different source file, ignore it. if (!SM.isFromMainFile(PPLoc)) { PP.Lex(PPTok); continue; } // If the raw file hits a preprocessor directive, they will be extra tokens // in the raw file that don't exist in the preprocsesed file. However, we // choose to preserve them in the output file and otherwise handle them // specially. if (RawTok.is(tok::hash) && RawTok.isAtStartOfLine()) { // If this is a #warning directive or #pragma mark (GNU extensions), // comment the line out. if (RawTokens[CurRawTok].is(tok::identifier)) { const IdentifierInfo *II = RawTokens[CurRawTok].getIdentifierInfo(); if (II->getName() == "warning") { // Comment out #warning. RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); } else if (II->getName() == "pragma" && RawTokens[CurRawTok+1].is(tok::identifier) && (RawTokens[CurRawTok+1].getIdentifierInfo()->getName() == "mark")) { // Comment out #pragma mark. RB.InsertTextAfter(SM.getFileOffset(RawTok.getLocation()), "//"); } } // Otherwise, if this is a #include or some other directive, just leave it // in the file by skipping over the line. RawTok = GetNextRawTok(RawTokens, CurRawTok, false); while (!RawTok.isAtStartOfLine() && RawTok.isNot(tok::eof)) RawTok = GetNextRawTok(RawTokens, CurRawTok, false); continue; } // Okay, both tokens are from the same file. Get their offsets from the // start of the file. unsigned PPOffs = SM.getFileOffset(PPLoc); unsigned RawOffs = SM.getFileOffset(RawTok.getLocation()); // If the offsets are the same and the token kind is the same, ignore them. if (PPOffs == RawOffs && isSameToken(RawTok, PPTok)) { RawTok = GetNextRawTok(RawTokens, CurRawTok, false); PP.Lex(PPTok); continue; } // If the PP token is farther along than the raw token, something was // deleted. Comment out the raw token. if (RawOffs <= PPOffs) { // Comment out a whole run of tokens instead of bracketing each one with // comments. Add a leading space if RawTok didn't have one. bool HasSpace = RawTok.hasLeadingSpace(); RB.InsertTextAfter(RawOffs, &" /*"[HasSpace]); unsigned EndPos; do { EndPos = RawOffs+RawTok.getLength(); RawTok = GetNextRawTok(RawTokens, CurRawTok, true); RawOffs = SM.getFileOffset(RawTok.getLocation()); if (RawTok.is(tok::comment)) { // Skip past the comment. RawTok = GetNextRawTok(RawTokens, CurRawTok, false); break; } } while (RawOffs <= PPOffs && !RawTok.isAtStartOfLine() && (PPOffs != RawOffs || !isSameToken(RawTok, PPTok))); RB.InsertTextBefore(EndPos, "*/"); continue; } // Otherwise, there was a replacement an expansion. Insert the new token // in the output buffer. Insert the whole run of new tokens at once to get // them in the right order. unsigned InsertPos = PPOffs; std::string Expansion; while (PPOffs < RawOffs) { Expansion += ' ' + PP.getSpelling(PPTok); PP.Lex(PPTok); PPLoc = SM.getExpansionLoc(PPTok.getLocation()); PPOffs = SM.getFileOffset(PPLoc); } Expansion += ' '; RB.InsertTextBefore(InsertPos, Expansion); } // Get the buffer corresponding to MainFileID. If we haven't changed it, then // we are done. if (const RewriteBuffer *RewriteBuf = Rewrite.getRewriteBufferFor(SM.getMainFileID())) { //printf("Changed:\n"); *OS << std::string(RewriteBuf->begin(), RewriteBuf->end()); } else { fprintf(stderr, "No changes\n"); } OS->flush(); }
/// HighlightMacros - This uses the macro table state from the end of the /// file, to re-expand macros and insert (into the HTML) information about the /// macro expansions. This won't be perfectly perfect, but it will be /// reasonably close. void html::HighlightMacros(Rewriter &R, FileID FID, Preprocessor& PP) { // Re-lex the raw token stream into a token buffer. const SourceManager &SM = PP.getSourceManager(); std::vector<Token> TokenStream; Lexer L(FID, SM, PP.getLangOptions()); // Lex all the tokens in raw mode, to avoid entering #includes or expanding // macros. while (1) { Token Tok; L.LexFromRawLexer(Tok); // If this is a # at the start of a line, discard it from the token stream. // We don't want the re-preprocess step to see #defines, #includes or other // preprocessor directives. if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) continue; // If this is a ## token, change its kind to unknown so that repreprocessing // it will not produce an error. if (Tok.is(tok::hashhash)) Tok.setKind(tok::unknown); // If this raw token is an identifier, the raw lexer won't have looked up // the corresponding identifier info for it. Do this now so that it will be // macro expanded when we re-preprocess it. if (Tok.is(tok::identifier)) { // Change the kind of this identifier to the appropriate token kind, e.g. // turning "for" into a keyword. Tok.setKind(PP.LookUpIdentifierInfo(Tok)->getTokenID()); } TokenStream.push_back(Tok); if (Tok.is(tok::eof)) break; } // Temporarily change the diagnostics object so that we ignore any generated // diagnostics from this pass. IgnoringDiagClient TmpDC; Diagnostic TmpDiags(&TmpDC); Diagnostic *OldDiags = &PP.getDiagnostics(); PP.setDiagnostics(TmpDiags); // Inform the preprocessor that we don't want comments. PP.SetCommentRetentionState(false, false); // Enter the tokens we just lexed. This will cause them to be macro expanded // but won't enter sub-files (because we removed #'s). PP.EnterTokenStream(&TokenStream[0], TokenStream.size(), false, false); TokenConcatenation ConcatInfo(PP); // Lex all the tokens. Token Tok; PP.Lex(Tok); while (Tok.isNot(tok::eof)) { // Ignore non-macro tokens. if (!Tok.getLocation().isMacroID()) { PP.Lex(Tok); continue; } // Okay, we have the first token of a macro expansion: highlight the // instantiation by inserting a start tag before the macro instantiation and // end tag after it. std::pair<SourceLocation, SourceLocation> LLoc = SM.getInstantiationRange(Tok.getLocation()); // Ignore tokens whose instantiation location was not the main file. if (SM.getFileID(LLoc.first) != FID) { PP.Lex(Tok); continue; } assert(SM.getFileID(LLoc.second) == FID && "Start and end of expansion must be in the same ultimate file!"); std::string Expansion = PP.getSpelling(Tok); unsigned LineLen = Expansion.size(); Token PrevTok = Tok; // Okay, eat this token, getting the next one. PP.Lex(Tok); // Skip all the rest of the tokens that are part of this macro // instantiation. It would be really nice to pop up a window with all the // spelling of the tokens or something. while (!Tok.is(tok::eof) && SM.getInstantiationLoc(Tok.getLocation()) == LLoc.first) { // Insert a newline if the macro expansion is getting large. if (LineLen > 60) { Expansion += "<br>"; LineLen = 0; } LineLen -= Expansion.size(); // If the tokens were already space separated, or if they must be to avoid // them being implicitly pasted, add a space between them. if (Tok.hasLeadingSpace() || ConcatInfo.AvoidConcat(PrevTok, Tok)) Expansion += ' '; // Escape any special characters in the token text. Expansion += EscapeText(PP.getSpelling(Tok)); LineLen += Expansion.size(); PrevTok = Tok; PP.Lex(Tok); } // Insert the expansion as the end tag, so that multi-line macros all get // highlighted. Expansion = "<span class='expansion'>" + Expansion + "</span></span>"; HighlightRange(R, LLoc.first, LLoc.second, "<span class='macro'>", Expansion.c_str()); } // Restore diagnostics object back to its own thing. PP.setDiagnostics(*OldDiags); }
/// HighlightMacros - This uses the macro table state from the end of the /// file, to re-expand macros and insert (into the HTML) information about the /// macro expansions. This won't be perfectly perfect, but it will be /// reasonably close. void html::HighlightMacros(Rewriter &R, FileID FID, const Preprocessor& PP) { // Re-lex the raw token stream into a token buffer. const SourceManager &SM = PP.getSourceManager(); std::vector<Token> TokenStream; const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); Lexer L(FID, FromFile, SM, PP.getLangOpts()); // Lex all the tokens in raw mode, to avoid entering #includes or expanding // macros. while (1) { Token Tok; L.LexFromRawLexer(Tok); // If this is a # at the start of a line, discard it from the token stream. // We don't want the re-preprocess step to see #defines, #includes or other // preprocessor directives. if (Tok.is(tok::hash) && Tok.isAtStartOfLine()) continue; // If this is a ## token, change its kind to unknown so that repreprocessing // it will not produce an error. if (Tok.is(tok::hashhash)) Tok.setKind(tok::unknown); // If this raw token is an identifier, the raw lexer won't have looked up // the corresponding identifier info for it. Do this now so that it will be // macro expanded when we re-preprocess it. if (Tok.is(tok::raw_identifier)) PP.LookUpIdentifierInfo(Tok); TokenStream.push_back(Tok); if (Tok.is(tok::eof)) break; } // Temporarily change the diagnostics object so that we ignore any generated // diagnostics from this pass. DiagnosticsEngine TmpDiags(PP.getDiagnostics().getDiagnosticIDs(), &PP.getDiagnostics().getDiagnosticOptions(), new IgnoringDiagConsumer); // FIXME: This is a huge hack; we reuse the input preprocessor because we want // its state, but we aren't actually changing it (we hope). This should really // construct a copy of the preprocessor. Preprocessor &TmpPP = const_cast<Preprocessor&>(PP); DiagnosticsEngine *OldDiags = &TmpPP.getDiagnostics(); TmpPP.setDiagnostics(TmpDiags); // Inform the preprocessor that we don't want comments. TmpPP.SetCommentRetentionState(false, false); // We don't want pragmas either. Although we filtered out #pragma, removing // _Pragma and __pragma is much harder. bool PragmasPreviouslyEnabled = TmpPP.getPragmasEnabled(); TmpPP.setPragmasEnabled(false); // Enter the tokens we just lexed. This will cause them to be macro expanded // but won't enter sub-files (because we removed #'s). TmpPP.EnterTokenStream(TokenStream, false); TokenConcatenation ConcatInfo(TmpPP); // Lex all the tokens. Token Tok; TmpPP.Lex(Tok); while (Tok.isNot(tok::eof)) { // Ignore non-macro tokens. if (!Tok.getLocation().isMacroID()) { TmpPP.Lex(Tok); continue; } // Okay, we have the first token of a macro expansion: highlight the // expansion by inserting a start tag before the macro expansion and // end tag after it. std::pair<SourceLocation, SourceLocation> LLoc = SM.getExpansionRange(Tok.getLocation()); // Ignore tokens whose instantiation location was not the main file. if (SM.getFileID(LLoc.first) != FID) { TmpPP.Lex(Tok); continue; } assert(SM.getFileID(LLoc.second) == FID && "Start and end of expansion must be in the same ultimate file!"); std::string Expansion = EscapeText(TmpPP.getSpelling(Tok)); unsigned LineLen = Expansion.size(); Token PrevPrevTok; Token PrevTok = Tok; // Okay, eat this token, getting the next one. TmpPP.Lex(Tok); // Skip all the rest of the tokens that are part of this macro // instantiation. It would be really nice to pop up a window with all the // spelling of the tokens or something. while (!Tok.is(tok::eof) && SM.getExpansionLoc(Tok.getLocation()) == LLoc.first) { // Insert a newline if the macro expansion is getting large. if (LineLen > 60) { Expansion += "<br>"; LineLen = 0; } LineLen -= Expansion.size(); // If the tokens were already space separated, or if they must be to avoid // them being implicitly pasted, add a space between them. if (Tok.hasLeadingSpace() || ConcatInfo.AvoidConcat(PrevPrevTok, PrevTok, Tok)) Expansion += ' '; // Escape any special characters in the token text. Expansion += EscapeText(TmpPP.getSpelling(Tok)); LineLen += Expansion.size(); PrevPrevTok = PrevTok; PrevTok = Tok; TmpPP.Lex(Tok); } // Insert the expansion as the end tag, so that multi-line macros all get // highlighted. Expansion = "<span class='expansion'>" + Expansion + "</span></span>"; HighlightRange(R, LLoc.first, LLoc.second, "<span class='macro'>", Expansion.c_str()); } // Restore the preprocessor's old state. TmpPP.setDiagnostics(*OldDiags); TmpPP.setPragmasEnabled(PragmasPreviouslyEnabled); }
void DependencyCollector::attachToPreprocessor(Preprocessor &PP) { PP.addPPCallbacks( llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager())); }
/// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(Diagnostic &D, Preprocessor &PP) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); SaveStorageSpecifierAsWritten(); // Check the type specifier components first. SourceManager &SrcMgr = PP.getSourceManager(); // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (TypeSpecSign != TSS_unspecified) { Diag(D, TSSLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } // Only char/int are valid with vector bool. (PIM 2.1) if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && (TypeSpecType != TST_int)) || TypeAltiVecPixel) { Diag(D, TSTLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType)); } // Only 'short' is valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short)) Diag(D, TSWLoc, SrcMgr, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSW)TypeSpecWidth); // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; } if (TypeAltiVecPixel) { //TODO: perform validation TypeSpecType = TST_int; TypeSpecSign = TSS_unsigned; TypeSpecWidth = TSW_short; TypeSpecOwned = false; } } // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { Diag(D, TSSLoc, SrcMgr, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType); // signed double -> double. TypeSpecSign = TSS_unspecified; } } // Validate the width of the type. switch (TypeSpecWidth) { case TSW_unspecified: break; case TSW_short: // short int case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { Diag(D, TSWLoc, SrcMgr, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; TypeSpecOwned = false; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { Diag(D, TSWLoc, SrcMgr, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecType = TST_int; TypeSpecOwned = false; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, SrcMgr, diag::ext_plain_complex) << FixItHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. Diag(D, TSTLoc, SrcMgr, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { Diag(D, TSCLoc, SrcMgr, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType); TypeSpecComplex = TSC_unspecified; } } // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && getStorageClassSpec()) { DeclSpec::SCS SC = getStorageClassSpec(); const char *SpecName = getSpecifierName(SC); SourceLocation SCLoc = getStorageClassSpecLoc(); SourceLocation SCEndLoc = SCLoc.getFileLocWithOffset(strlen(SpecName)); Diag(D, SCLoc, SrcMgr, diag::err_friend_storage_spec) << SpecName << FixItHint::CreateRemoval(SourceRange(SCLoc, SCEndLoc)); ClearStorageClassSpecs(); } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? }
void DependencyCollector::attachToPreprocessor(Preprocessor &PP) { PP.addPPCallbacks(new DepCollectorPPCallbacks(*this, PP.getSourceManager())); }
/// InitializePreprocessor - Initialize the preprocessor getting it and the /// environment ready to process a single file. This returns true on error. /// void clang::InitializePreprocessor(Preprocessor &PP, const PreprocessorOptions &InitOpts, const HeaderSearchOptions &HSOpts, const FrontendOptions &FEOpts) { const LangOptions &LangOpts = PP.getLangOpts(); std::string PredefineBuffer; PredefineBuffer.reserve(4080); llvm::raw_string_ostream Predefines(PredefineBuffer); MacroBuilder Builder(Predefines); InitializeFileRemapping(PP.getDiagnostics(), PP.getSourceManager(), PP.getFileManager(), InitOpts); // Emit line markers for various builtin sections of the file. We don't do // this in asm preprocessor mode, because "# 4" is not a line marker directive // in this mode. if (!PP.getLangOpts().AsmPreprocessor) Builder.append("# 1 \"<built-in>\" 3"); // Install things like __POWERPC__, __GNUC__, etc into the macro table. if (InitOpts.UsePredefines) { InitializePredefinedMacros(PP.getTargetInfo(), LangOpts, FEOpts, Builder); // Install definitions to make Objective-C++ ARC work well with various // C++ Standard Library implementations. if (LangOpts.ObjC1 && LangOpts.CPlusPlus && LangOpts.ObjCAutoRefCount) { switch (InitOpts.ObjCXXARCStandardLibrary) { case ARCXX_nolib: case ARCXX_libcxx: break; case ARCXX_libstdcxx: AddObjCXXARCLibstdcxxDefines(LangOpts, Builder); break; } } } // Even with predefines off, some macros are still predefined. // These should all be defined in the preprocessor according to the // current language configuration. InitializeStandardPredefinedMacros(PP.getTargetInfo(), PP.getLangOpts(), FEOpts, Builder); // Add on the predefines from the driver. Wrap in a #line directive to report // that they come from the command line. if (!PP.getLangOpts().AsmPreprocessor) Builder.append("# 1 \"<command line>\" 1"); // Process #define's and #undef's in the order they are given. for (unsigned i = 0, e = InitOpts.Macros.size(); i != e; ++i) { if (InitOpts.Macros[i].second) // isUndef Builder.undefineMacro(InitOpts.Macros[i].first); else DefineBuiltinMacro(Builder, InitOpts.Macros[i].first, PP.getDiagnostics()); } // If -imacros are specified, include them now. These are processed before // any -include directives. for (unsigned i = 0, e = InitOpts.MacroIncludes.size(); i != e; ++i) AddImplicitIncludeMacros(Builder, InitOpts.MacroIncludes[i], PP.getFileManager()); // Process -include-pch/-include-pth directives. if (!InitOpts.ImplicitPCHInclude.empty()) AddImplicitIncludePCH(Builder, PP, InitOpts.ImplicitPCHInclude); if (!InitOpts.ImplicitPTHInclude.empty()) AddImplicitIncludePTH(Builder, PP, InitOpts.ImplicitPTHInclude); // Process -include directives. for (unsigned i = 0, e = InitOpts.Includes.size(); i != e; ++i) { const std::string &Path = InitOpts.Includes[i]; AddImplicitInclude(Builder, Path, PP.getFileManager()); } // Exit the command line and go back to <built-in> (2 is LC_LEAVE). if (!PP.getLangOpts().AsmPreprocessor) Builder.append("# 1 \"<built-in>\" 2"); // Instruct the preprocessor to skip the preamble. PP.setSkipMainFilePreamble(InitOpts.PrecompiledPreambleBytes.first, InitOpts.PrecompiledPreambleBytes.second); // Copy PredefinedBuffer into the Preprocessor. PP.setPredefines(Predefines.str()); // Initialize the header search object. ApplyHeaderSearchOptions(PP.getHeaderSearchInfo(), HSOpts, PP.getLangOpts(), PP.getTargetInfo().getTriple()); }
void DependencyCollector::attachToPreprocessor(Preprocessor &PP) { PP.addPPCallbacks( llvm::make_unique<DepCollectorPPCallbacks>(*this, PP.getSourceManager())); PP.getHeaderSearchInfo().getModuleMap().addModuleMapCallbacks( llvm::make_unique<DepCollectorMMCallbacks>(*this)); }
/// Finish - This does final analysis of the declspec, rejecting things like /// "_Imaginary" (lacking an FP type). This returns a diagnostic to issue or /// diag::NUM_DIAGNOSTICS if there is no error. After calling this method, /// DeclSpec is guaranteed self-consistent, even if an error occurred. void DeclSpec::Finish(DiagnosticsEngine &D, Preprocessor &PP, const PrintingPolicy &Policy) { // Before possibly changing their values, save specs as written. SaveWrittenBuiltinSpecs(); // Check the type specifier components first. // If decltype(auto) is used, no other type specifiers are permitted. if (TypeSpecType == TST_decltype_auto && (TypeSpecWidth != TSW_unspecified || TypeSpecComplex != TSC_unspecified || TypeSpecSign != TSS_unspecified || TypeAltiVecVector || TypeAltiVecPixel || TypeAltiVecBool || TypeQualifiers)) { const unsigned NumLocs = 8; SourceLocation ExtraLocs[NumLocs] = { TSWLoc, TSCLoc, TSSLoc, AltiVecLoc, TQ_constLoc, TQ_restrictLoc, TQ_volatileLoc, TQ_atomicLoc }; FixItHint Hints[NumLocs]; SourceLocation FirstLoc; for (unsigned I = 0; I != NumLocs; ++I) { if (!ExtraLocs[I].isInvalid()) { if (FirstLoc.isInvalid() || PP.getSourceManager().isBeforeInTranslationUnit(ExtraLocs[I], FirstLoc)) FirstLoc = ExtraLocs[I]; Hints[I] = FixItHint::CreateRemoval(ExtraLocs[I]); } } TypeSpecWidth = TSW_unspecified; TypeSpecComplex = TSC_unspecified; TypeSpecSign = TSS_unspecified; TypeAltiVecVector = TypeAltiVecPixel = TypeAltiVecBool = false; TypeQualifiers = 0; Diag(D, TSTLoc, diag::err_decltype_auto_cannot_be_combined) << Hints[0] << Hints[1] << Hints[2] << Hints[3] << Hints[4] << Hints[5] << Hints[6] << Hints[7]; } // Validate and finalize AltiVec vector declspec. if (TypeAltiVecVector) { if (TypeAltiVecBool) { // Sign specifiers are not allowed with vector bool. (PIM 2.1) if (TypeSpecSign != TSS_unspecified) { Diag(D, TSSLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSS)TypeSpecSign); } // Only char/int are valid with vector bool. (PIM 2.1) if (((TypeSpecType != TST_unspecified) && (TypeSpecType != TST_char) && (TypeSpecType != TST_int)) || TypeAltiVecPixel) { Diag(D, TSTLoc, diag::err_invalid_vector_bool_decl_spec) << (TypeAltiVecPixel ? "__pixel" : getSpecifierName((TST)TypeSpecType, Policy)); } // Only 'short' and 'long long' are valid with vector bool. (PIM 2.1) if ((TypeSpecWidth != TSW_unspecified) && (TypeSpecWidth != TSW_short) && (TypeSpecWidth != TSW_longlong)) Diag(D, TSWLoc, diag::err_invalid_vector_bool_decl_spec) << getSpecifierName((TSW)TypeSpecWidth); // vector bool long long requires VSX support. if ((TypeSpecWidth == TSW_longlong) && (!PP.getTargetInfo().hasFeature("vsx")) && (!PP.getTargetInfo().hasFeature("power8-vector"))) Diag(D, TSTLoc, diag::err_invalid_vector_long_long_decl_spec); // Elements of vector bool are interpreted as unsigned. (PIM 2.1) if ((TypeSpecType == TST_char) || (TypeSpecType == TST_int) || (TypeSpecWidth != TSW_unspecified)) TypeSpecSign = TSS_unsigned; } else if (TypeSpecType == TST_double) { // vector long double and vector long long double are never allowed. // vector double is OK for Power7 and later. if (TypeSpecWidth == TSW_long || TypeSpecWidth == TSW_longlong) Diag(D, TSWLoc, diag::err_invalid_vector_long_double_decl_spec); else if (!PP.getTargetInfo().hasFeature("vsx")) Diag(D, TSTLoc, diag::err_invalid_vector_double_decl_spec); } else if (TypeSpecWidth == TSW_long) { Diag(D, TSWLoc, diag::warn_vector_long_decl_spec_combination) << getSpecifierName((TST)TypeSpecType, Policy); } if (TypeAltiVecPixel) { //TODO: perform validation TypeSpecType = TST_int; TypeSpecSign = TSS_unsigned; TypeSpecWidth = TSW_short; TypeSpecOwned = false; } } // signed/unsigned are only valid with int/char/wchar_t. if (TypeSpecSign != TSS_unspecified) { if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // unsigned -> unsigned int, signed -> signed int. else if (TypeSpecType != TST_int && TypeSpecType != TST_int128 && TypeSpecType != TST_char && TypeSpecType != TST_wchar) { Diag(D, TSSLoc, diag::err_invalid_sign_spec) << getSpecifierName((TST)TypeSpecType, Policy); // signed double -> double. TypeSpecSign = TSS_unspecified; } } // Validate the width of the type. switch (TypeSpecWidth) { case TSW_unspecified: break; case TSW_short: // short int case TSW_longlong: // long long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // short -> short int, long long -> long long int. else if (TypeSpecType != TST_int) { Diag(D, TSWLoc, TypeSpecWidth == TSW_short ? diag::err_invalid_short_spec : diag::err_invalid_longlong_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } break; case TSW_long: // long double, long int if (TypeSpecType == TST_unspecified) TypeSpecType = TST_int; // long -> long int. else if (TypeSpecType != TST_int && TypeSpecType != TST_double) { Diag(D, TSWLoc, diag::err_invalid_long_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecType = TST_int; TypeSpecOwned = false; } break; } // TODO: if the implementation does not implement _Complex or _Imaginary, // disallow their use. Need information about the backend. if (TypeSpecComplex != TSC_unspecified) { if (TypeSpecType == TST_unspecified) { Diag(D, TSCLoc, diag::ext_plain_complex) << FixItHint::CreateInsertion( PP.getLocForEndOfToken(getTypeSpecComplexLoc()), " double"); TypeSpecType = TST_double; // _Complex -> _Complex double. } else if (TypeSpecType == TST_int || TypeSpecType == TST_char) { // Note that this intentionally doesn't include _Complex _Bool. if (!PP.getLangOpts().CPlusPlus) Diag(D, TSTLoc, diag::ext_integer_complex); } else if (TypeSpecType != TST_float && TypeSpecType != TST_double) { Diag(D, TSCLoc, diag::err_invalid_complex_spec) << getSpecifierName((TST)TypeSpecType, Policy); TypeSpecComplex = TSC_unspecified; } } // C11 6.7.1/3, C++11 [dcl.stc]p1, GNU TLS: __thread, thread_local and // _Thread_local can only appear with the 'static' and 'extern' storage class // specifiers. We also allow __private_extern__ as an extension. if (ThreadStorageClassSpec != TSCS_unspecified) { switch (StorageClassSpec) { case SCS_unspecified: case SCS_extern: case SCS_private_extern: case SCS_static: break; default: if (PP.getSourceManager().isBeforeInTranslationUnit( getThreadStorageClassSpecLoc(), getStorageClassSpecLoc())) Diag(D, getStorageClassSpecLoc(), diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getThreadStorageClassSpec()) << SourceRange(getThreadStorageClassSpecLoc()); else Diag(D, getThreadStorageClassSpecLoc(), diag::err_invalid_decl_spec_combination) << DeclSpec::getSpecifierName(getStorageClassSpec()) << SourceRange(getStorageClassSpecLoc()); // Discard the thread storage class specifier to recover. ThreadStorageClassSpec = TSCS_unspecified; ThreadStorageClassSpecLoc = SourceLocation(); } } // If no type specifier was provided and we're parsing a language where // the type specifier is not optional, but we got 'auto' as a storage // class specifier, then assume this is an attempt to use C++0x's 'auto' // type specifier. if (PP.getLangOpts().CPlusPlus && TypeSpecType == TST_unspecified && StorageClassSpec == SCS_auto) { TypeSpecType = TST_auto; StorageClassSpec = SCS_unspecified; TSTLoc = TSTNameLoc = StorageClassSpecLoc; StorageClassSpecLoc = SourceLocation(); } // Diagnose if we've recovered from an ill-formed 'auto' storage class // specifier in a pre-C++11 dialect of C++. if (!PP.getLangOpts().CPlusPlus11 && TypeSpecType == TST_auto) Diag(D, TSTLoc, diag::ext_auto_type_specifier); if (PP.getLangOpts().CPlusPlus && !PP.getLangOpts().CPlusPlus11 && StorageClassSpec == SCS_auto) Diag(D, StorageClassSpecLoc, diag::warn_auto_storage_class) << FixItHint::CreateRemoval(StorageClassSpecLoc); if (TypeSpecType == TST_char16 || TypeSpecType == TST_char32) Diag(D, TSTLoc, diag::warn_cxx98_compat_unicode_type) << (TypeSpecType == TST_char16 ? "char16_t" : "char32_t"); if (Constexpr_specified) Diag(D, ConstexprLoc, diag::warn_cxx98_compat_constexpr); // C++ [class.friend]p6: // No storage-class-specifier shall appear in the decl-specifier-seq // of a friend declaration. if (isFriendSpecified() && (getStorageClassSpec() || getThreadStorageClassSpec())) { SmallString<32> SpecName; SourceLocation SCLoc; FixItHint StorageHint, ThreadHint; if (DeclSpec::SCS SC = getStorageClassSpec()) { SpecName = getSpecifierName(SC); SCLoc = getStorageClassSpecLoc(); StorageHint = FixItHint::CreateRemoval(SCLoc); } if (DeclSpec::TSCS TSC = getThreadStorageClassSpec()) { if (!SpecName.empty()) SpecName += " "; SpecName += getSpecifierName(TSC); SCLoc = getThreadStorageClassSpecLoc(); ThreadHint = FixItHint::CreateRemoval(SCLoc); } Diag(D, SCLoc, diag::err_friend_decl_spec) << SpecName << StorageHint << ThreadHint; ClearStorageClassSpecs(); } // C++11 [dcl.fct.spec]p5: // The virtual specifier shall be used only in the initial // declaration of a non-static class member function; // C++11 [dcl.fct.spec]p6: // The explicit specifier shall be used only in the declaration of // a constructor or conversion function within its class // definition; if (isFriendSpecified() && (isVirtualSpecified() || isExplicitSpecified())) { StringRef Keyword; SourceLocation SCLoc; if (isVirtualSpecified()) { Keyword = "virtual"; SCLoc = getVirtualSpecLoc(); } else { Keyword = "explicit"; SCLoc = getExplicitSpecLoc(); } FixItHint Hint = FixItHint::CreateRemoval(SCLoc); Diag(D, SCLoc, diag::err_friend_decl_spec) << Keyword << Hint; FS_virtual_specified = FS_explicit_specified = false; FS_virtualLoc = FS_explicitLoc = SourceLocation(); } assert(!TypeSpecOwned || isDeclRep((TST) TypeSpecType)); // Okay, now we can infer the real type. // TODO: return "auto function" and other bad things based on the real type. // 'data definition has no type or storage class'? }
/// SyntaxHighlight - Relex the specified FileID and annotate the HTML with /// information about keywords, macro expansions etc. This uses the macro /// table state from the end of the file, so it won't be perfectly perfect, /// but it will be reasonably close. void html::SyntaxHighlight(Rewriter &R, FileID FID, const Preprocessor &PP) { RewriteBuffer &RB = R.getEditBuffer(FID); const SourceManager &SM = PP.getSourceManager(); const llvm::MemoryBuffer *FromFile = SM.getBuffer(FID); Lexer L(FID, FromFile, SM, PP.getLangOpts()); const char *BufferStart = L.getBuffer().data(); // Inform the preprocessor that we want to retain comments as tokens, so we // can highlight them. L.SetCommentRetentionState(true); // Lex all the tokens in raw mode, to avoid entering #includes or expanding // macros. Token Tok; L.LexFromRawLexer(Tok); while (Tok.isNot(tok::eof)) { // Since we are lexing unexpanded tokens, all tokens are from the main // FileID. unsigned TokOffs = SM.getFileOffset(Tok.getLocation()); unsigned TokLen = Tok.getLength(); switch (Tok.getKind()) { default: break; case tok::identifier: llvm_unreachable("tok::identifier in raw lexing mode!"); case tok::raw_identifier: { // Fill in Result.IdentifierInfo and update the token kind, // looking up the identifier in the identifier table. PP.LookUpIdentifierInfo(Tok); // If this is a pp-identifier, for a keyword, highlight it as such. if (Tok.isNot(tok::identifier)) HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, "<span class='keyword'>", "</span>"); break; } case tok::comment: HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, "<span class='comment'>", "</span>"); break; case tok::utf8_string_literal: // Chop off the u part of u8 prefix ++TokOffs; --TokLen; // FALL THROUGH to chop the 8 case tok::wide_string_literal: case tok::utf16_string_literal: case tok::utf32_string_literal: // Chop off the L, u, U or 8 prefix ++TokOffs; --TokLen; // FALL THROUGH. case tok::string_literal: // FIXME: Exclude the optional ud-suffix from the highlighted range. HighlightRange(RB, TokOffs, TokOffs+TokLen, BufferStart, "<span class='string_literal'>", "</span>"); break; case tok::hash: { // If this is a preprocessor directive, all tokens to end of line are too. if (!Tok.isAtStartOfLine()) break; // Eat all of the tokens until we get to the next one at the start of // line. unsigned TokEnd = TokOffs+TokLen; L.LexFromRawLexer(Tok); while (!Tok.isAtStartOfLine() && Tok.isNot(tok::eof)) { TokEnd = SM.getFileOffset(Tok.getLocation())+Tok.getLength(); L.LexFromRawLexer(Tok); } // Find end of line. This is a hack. HighlightRange(RB, TokOffs, TokEnd, BufferStart, "<span class='directive'>", "</span>"); // Don't skip the next token. continue; } } L.LexFromRawLexer(Tok); } }