/// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM) { if (Loc.isInvalid()) { emitModuleBuildStack(SM); return; } PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); if (PLoc.isInvalid()) return; // If this source location was imported from a module, print the module // import stack rather than the // FIXME: We want submodule granularity here. std::pair<SourceLocation, StringRef> Imported = SM.getModuleImportLoc(Loc); if (!Imported.second.empty()) { // This location was imported by a module. Emit the module import stack. emitImportStackRecursively(Imported.first, Imported.second, SM); return; } // Emit the other include frames first. emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); // Emit the inclusion text/note. emitIncludeLocation(Loc, PLoc, SM); }
/// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. void DiagnosticRenderer::emitIncludeStackRecursively(SourceLocation Loc, const SourceManager &SM) { PresumedLoc PLoc = SM.getPresumedLoc(Loc, DiagOpts->ShowPresumedLoc); if (PLoc.isInvalid()) return; // Emit the other include frames first. emitIncludeStackRecursively(PLoc.getIncludeLoc(), SM); // Emit the inclusion text/note. emitIncludeLocation(Loc, PLoc, SM); }
void DiagnosticRenderer::emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> FixItHints, const SourceManager *SM, DiagOrStoredDiag D) { assert(SM || Loc.isInvalid()); beginDiagnostic(D, Level); PresumedLoc PLoc; if (Loc.isValid()) { PLoc = SM->getPresumedLocForDisplay(Loc); // First, if this diagnostic is not in the main file, print out the // "included from" lines. emitIncludeStack(PLoc.getIncludeLoc(), Level, *SM); } // Next, emit the actual diagnostic message. emitDiagnosticMessage(Loc, PLoc, Level, Message, Ranges, SM, D); // Only recurse if we have a valid location. if (Loc.isValid()) { // Get the ranges into a local array we can hack on. SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), Ranges.end()); llvm::SmallVector<FixItHint, 8> MergedFixits; if (!FixItHints.empty()) { mergeFixits(FixItHints, *SM, LangOpts, MergedFixits); FixItHints = MergedFixits; } for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) if (I->RemoveRange.isValid()) MutableRanges.push_back(I->RemoveRange); unsigned MacroDepth = 0; emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, *SM, MacroDepth); } LastLoc = Loc; LastLevel = Level; endDiagnostic(D, Level); }
void TextDiagnosticPrinter:: PrintIncludeStack(SourceLocation Loc, const SourceManager &SM) { if (Loc.isInvalid()) return; PresumedLoc PLoc = SM.getPresumedLoc(Loc); // Print out the other include frames first. PrintIncludeStack(PLoc.getIncludeLoc(), SM); if (DiagOpts->ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "In included file:\n"; }
static void getInclusions(const SrcMgr::SLocEntry &(SourceManager::*Getter)(unsigned, bool*) const, unsigned n, CXTranslationUnit TU, CXInclusionVisitor CB, CXClientData clientData) { ASTUnit *CXXUnit = cxtu::getASTUnit(TU); SourceManager &SM = CXXUnit->getSourceManager(); ASTContext &Ctx = CXXUnit->getASTContext(); SmallVector<CXSourceLocation, 10> InclusionStack; const bool HasPreamble = SM.getPreambleFileID().isValid(); for (unsigned i = 0 ; i < n ; ++i) { bool Invalid = false; const SrcMgr::SLocEntry &SL = (SM.*Getter)(i, &Invalid); if (!SL.isFile() || Invalid) continue; const SrcMgr::FileInfo &FI = SL.getFile(); if (!FI.getContentCache()->OrigEntry) continue; // If this is the main file, and there is a preamble, skip this SLoc. The // inclusions of the preamble already showed it. SourceLocation L = FI.getIncludeLoc(); if (HasPreamble && CXXUnit->isInMainFileID(L)) continue; // Build the inclusion stack. InclusionStack.clear(); while (L.isValid()) { PresumedLoc PLoc = SM.getPresumedLoc(L); InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L)); L = PLoc.isValid()? PLoc.getIncludeLoc() : SourceLocation(); } // If there is a preamble, the last entry is the "inclusion" of that // preamble into the main file, which has the bogus entry of main.c:1:1 if (HasPreamble && !InclusionStack.empty()) InclusionStack.pop_back(); // Callback to the client. // FIXME: We should have a function to construct CXFiles. CB(static_cast<CXFile>( const_cast<FileEntry *>(FI.getContentCache()->OrigEntry)), InclusionStack.data(), InclusionStack.size(), clientData); } }
/// \brief Helper to recursivly walk up the include stack and print each layer /// on the way back down. void TextDiagnostic::emitIncludeStackRecursively(SourceLocation Loc) { if (Loc.isInvalid()) return; PresumedLoc PLoc = SM.getPresumedLoc(Loc); if (PLoc.isInvalid()) return; // Emit the other include frames first. emitIncludeStackRecursively(PLoc.getIncludeLoc()); if (DiagOpts.ShowLocation) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "In included file:\n"; }
void TextDiagnostic::emitDiagnostic(SourceLocation Loc, DiagnosticsEngine::Level Level, StringRef Message, ArrayRef<CharSourceRange> Ranges, ArrayRef<FixItHint> FixItHints) { PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Loc); // First, if this diagnostic is not in the main file, print out the // "included from" lines. emitIncludeStack(PLoc.getIncludeLoc(), Level); uint64_t StartOfLocationInfo = OS.tell(); // Next emit the location of this particular diagnostic. emitDiagnosticLoc(Loc, PLoc, Level, Ranges); if (DiagOpts.ShowColors) OS.resetColor(); printDiagnosticLevel(OS, Level, DiagOpts.ShowColors); printDiagnosticMessage(OS, Level, Message, OS.tell() - StartOfLocationInfo, DiagOpts.MessageLength, DiagOpts.ShowColors); // Only recurse if we have a valid location. if (Loc.isValid()) { // Get the ranges into a local array we can hack on. SmallVector<CharSourceRange, 20> MutableRanges(Ranges.begin(), Ranges.end()); for (ArrayRef<FixItHint>::const_iterator I = FixItHints.begin(), E = FixItHints.end(); I != E; ++I) if (I->RemoveRange.isValid()) MutableRanges.push_back(I->RemoveRange); unsigned MacroDepth = 0; emitMacroExpansionsAndCarets(Loc, Level, MutableRanges, FixItHints, MacroDepth); } LastLoc = Loc; LastLevel = Level; }
void clang_getInclusions(CXTranslationUnit TU, CXInclusionVisitor CB, CXClientData clientData) { ASTUnit *CXXUnit = static_cast<ASTUnit *>(TU); SourceManager &SM = CXXUnit->getSourceManager(); ASTContext &Ctx = CXXUnit->getASTContext(); llvm::SmallVector<CXSourceLocation, 10> InclusionStack; unsigned i = SM.sloc_loaded_entry_size(); unsigned n = SM.sloc_entry_size(); // In the case where all the SLocEntries are in an external source, traverse // those SLocEntries as well. This is the case where we are looking // at the inclusion stack of an AST/PCH file. if (i >= n) i = 0; for ( ; i < n ; ++i) { const SrcMgr::SLocEntry &SL = SM.getSLocEntry(i); if (!SL.isFile()) continue; const SrcMgr::FileInfo &FI = SL.getFile(); if (!FI.getContentCache()->Entry) continue; // Build the inclusion stack. SourceLocation L = FI.getIncludeLoc(); InclusionStack.clear(); while (L.isValid()) { PresumedLoc PLoc = SM.getPresumedLoc(L); InclusionStack.push_back(cxloc::translateSourceLocation(Ctx, L)); L = PLoc.getIncludeLoc(); } // Callback to the client. // FIXME: We should have a function to construct CXFiles. CB((CXFile) FI.getContentCache()->Entry, InclusionStack.data(), InclusionStack.size(), clientData); } }
/// \brief Prints an include stack when appropriate for a particular /// diagnostic level and location. /// /// This routine handles all the logic of suppressing particular include /// stacks (such as those for notes) and duplicate include stacks when /// repeated warnings occur within the same file. It also handles the logic /// of customizing the formatting and display of the include stack. /// /// \param Loc The diagnostic location. /// \param PLoc The presumed location of the diagnostic location. /// \param Level The diagnostic level of the message this stack pertains to. void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, const SourceManager &SM) { SourceLocation IncludeLoc = PLoc.getIncludeLoc(); // Skip redundant include stacks altogether. if (LastIncludeLoc == IncludeLoc) return; LastIncludeLoc = IncludeLoc; if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) return; if (!IncludeLoc.isValid()){ // TODO: Should ERROR } emitIncludeStackRecursively(IncludeLoc, SM); }
/// \brief Prints an include stack when appropriate for a particular /// diagnostic level and location. /// /// This routine handles all the logic of suppressing particular include /// stacks (such as those for notes) and duplicate include stacks when /// repeated warnings occur within the same file. It also handles the logic /// of customizing the formatting and display of the include stack. /// /// \param Loc The diagnostic location. /// \param PLoc The presumed location of the diagnostic location. /// \param Level The diagnostic level of the message this stack pertains to. void DiagnosticRenderer::emitIncludeStack(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, const SourceManager &SM) { SourceLocation IncludeLoc = PLoc.isInvalid() ? SourceLocation() : PLoc.getIncludeLoc(); // Skip redundant include stacks altogether. if (LastIncludeLoc == IncludeLoc) return; LastIncludeLoc = IncludeLoc; if (!DiagOpts->ShowNoteIncludeStack && Level == DiagnosticsEngine::Note) return; if (IncludeLoc.isValid()) emitIncludeStackRecursively(IncludeLoc, SM); else { emitModuleBuildStack(SM); emitImportStack(Loc, SM); } }
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Figure out which token this is. IdentifierInfo *II = Tok.getIdentifierInfo(); assert(II && "Can't be a macro without id info!"); // If this is an _Pragma or Microsoft __pragma directive, expand it, // invoke the pragma handler, then lex the token after it. if (II == Ident_Pragma) return Handle_Pragma(Tok); else if (II == Ident__pragma) // in non-MS mode this is null return HandleMicrosoft__pragma(Tok); ++NumBuiltinMacroExpanded; llvm::SmallString<128> TmpBuffer; llvm::raw_svector_ostream OS(TmpBuffer); // Set up the return result. Tok.setIdentifierInfo(0); Tok.clearFlag(Token::NeedsCleaning); if (II == Ident__LINE__) { // C99 6.10.8: "__LINE__: The presumed line number (within the current // source file) of the current source line (an integer constant)". This can // be affected by #line. SourceLocation Loc = Tok.getLocation(); // Advance to the location of the first _, this might not be the first byte // of the token if it starts with an escaped newline. Loc = AdvanceToTokenCharacter(Loc, 0); // One wrinkle here is that GCC expands __LINE__ to location of the *end* of // a macro expansion. This doesn't matter for object-like macros, but // can matter for a function-like macro that expands to contain __LINE__. // Skip down through expansion points until we find a file loc for the // end of the expansion history. Loc = SourceMgr.getExpansionRange(Loc).second; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); // __LINE__ expands to a simple numeric value. OS << (PLoc.isValid()? PLoc.getLine() : 1); Tok.setKind(tok::numeric_constant); } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { // C99 6.10.8: "__FILE__: The presumed name of the current source file (a // character string literal)". This can be affected by #line. PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); // __BASE_FILE__ is a GNU extension that returns the top of the presumed // #include stack instead of the current file. if (II == Ident__BASE_FILE__ && PLoc.isValid()) { SourceLocation NextLoc = PLoc.getIncludeLoc(); while (NextLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(NextLoc); if (PLoc.isInvalid()) break; NextLoc = PLoc.getIncludeLoc(); } } // Escape this filename. Turn '\' -> '\\' '"' -> '\"' llvm::SmallString<128> FN; if (PLoc.isValid()) { FN += PLoc.getFilename(); Lexer::Stringify(FN); OS << '"' << FN.str() << '"'; } Tok.setKind(tok::string_literal); } else if (II == Ident__DATE__) { if (!DATELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"Mmm dd yyyy\"")); Tok.setLocation(SourceMgr.createExpansionLoc(DATELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__TIME__) { if (!TIMELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"hh:mm:ss\"")); Tok.setLocation(SourceMgr.createExpansionLoc(TIMELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__INCLUDE_LEVEL__) { // Compute the presumed include depth of this token. This can be affected // by GNU line markers. unsigned Depth = 0; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); if (PLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); for (; PLoc.isValid(); ++Depth) PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); } // __INCLUDE_LEVEL__ expands to a simple numeric value. OS << Depth; Tok.setKind(tok::numeric_constant); } else if (II == Ident__TIMESTAMP__) { // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. // Get the file that we are lexing out of. If we're currently lexing from // a macro, dig into the include stack. const FileEntry *CurFile = 0; PreprocessorLexer *TheLexer = getCurrentFileLexer(); if (TheLexer) CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); const char *Result; if (CurFile) { time_t TT = CurFile->getModificationTime(); struct tm *TM = localtime(&TT); Result = asctime(TM); } else { Result = "??? ??? ?? ??:??:?? ????\n"; } // Surround the string with " and strip the trailing newline. OS << '"' << StringRef(Result, strlen(Result)-1) << '"'; Tok.setKind(tok::string_literal); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_feature || II == Ident__has_extension || II == Ident__has_builtin || II == Ident__has_attribute) { // The argument to these builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; IdentifierInfo *FeatureII = 0; // Read the '('. Lex(Tok); if (Tok.is(tok::l_paren)) { // Read the identifier Lex(Tok); if (Tok.is(tok::identifier)) { FeatureII = Tok.getIdentifierInfo(); // Read the ')'. Lex(Tok); if (Tok.is(tok::r_paren)) IsValid = true; } } bool Value = false; if (!IsValid) Diag(StartLoc, diag::err_feature_check_malformed); else if (II == Ident__has_builtin) { // Check for a builtin is trivial. Value = FeatureII->getBuiltinID() != 0; } else if (II == Ident__has_attribute) Value = HasAttribute(FeatureII); else if (II == Ident__has_extension) Value = HasExtension(*this, FeatureII); else { assert(II == Ident__has_feature && "Must be feature check"); Value = HasFeature(*this, FeatureII); } OS << (int)Value; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_include || II == Ident__has_include_next) { // The argument to these two builtins should be a parenthesized // file name string literal using angle brackets (<>) or // double-quotes (""). bool Value; if (II == Ident__has_include) Value = EvaluateHasInclude(Tok, II, *this); else Value = EvaluateHasIncludeNext(Tok, II, *this); OS << (int)Value; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_warning) { // The argument should be a parenthesized string literal. // The argument to these builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; bool Value = false; // Read the '('. Lex(Tok); do { if (Tok.is(tok::l_paren)) { // Read the string. Lex(Tok); // We need at least one string literal. if (!Tok.is(tok::string_literal)) { StartLoc = Tok.getLocation(); IsValid = false; // Eat tokens until ')'. do Lex(Tok); while (!(Tok.is(tok::r_paren) || Tok.is(tok::eod))); break; } // String concatenation allows multiple strings, which can even come // from macro expansion. SmallVector<Token, 4> StrToks; while (Tok.is(tok::string_literal)) { StrToks.push_back(Tok); LexUnexpandedToken(Tok); } // Is the end a ')'? if (!(IsValid = Tok.is(tok::r_paren))) break; // Concatenate and parse the strings. StringLiteralParser Literal(&StrToks[0], StrToks.size(), *this); assert(Literal.isAscii() && "Didn't allow wide strings in"); if (Literal.hadError) break; if (Literal.Pascal) { Diag(Tok, diag::warn_pragma_diagnostic_invalid); break; } StringRef WarningName(Literal.GetString()); if (WarningName.size() < 3 || WarningName[0] != '-' || WarningName[1] != 'W') { Diag(StrToks[0].getLocation(), diag::warn_has_warning_invalid_option); break; } // Finally, check if the warning flags maps to a diagnostic group. // We construct a SmallVector here to talk to getDiagnosticIDs(). // Although we don't use the result, this isn't a hot path, and not // worth special casing. llvm::SmallVector<diag::kind, 10> Diags; Value = !getDiagnostics().getDiagnosticIDs()-> getDiagnosticsInGroup(WarningName.substr(2), Diags); } } while (false); if (!IsValid) Diag(StartLoc, diag::err_warning_check_malformed); OS << (int)Value; Tok.setKind(tok::numeric_constant); } else { llvm_unreachable("Unknown identifier!"); } CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation(), Tok.getLocation()); }
void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) { // Keeps track of the the starting position of the location // information (e.g., "foo.c:10:4:") that precedes the error // message. We use this information to determine how long the // file+line+column number prefix is. uint64_t StartOfLocationInfo = OS.tell(); if (!Prefix.empty()) OS << Prefix << ": "; // If the location is specified, print out a file/line/col and include trace // if enabled. if (Info.getLocation().isValid()) { const SourceManager &SM = Info.getLocation().getManager(); PresumedLoc PLoc = SM.getPresumedLoc(Info.getLocation()); unsigned LineNo = PLoc.getLine(); // First, if this diagnostic is not in the main file, print out the // "included from" lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { LastWarningLoc = PLoc.getIncludeLoc(); PrintIncludeStack(LastWarningLoc, SM); StartOfLocationInfo = OS.tell(); } // Compute the column number. if (DiagOpts->ShowLocation) { if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); // Emit a Visual Studio compatible line number syntax. if (LangOpts && LangOpts->Microsoft) { OS << PLoc.getFilename() << '(' << LineNo << ')'; OS << " : "; } else { OS << PLoc.getFilename() << ':' << LineNo << ':'; if (DiagOpts->ShowColumn) if (unsigned ColNo = PLoc.getColumn()) OS << ColNo << ':'; } if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); bool PrintedRange = false; for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { // Ignore invalid ranges. if (!Info.getRange(i).isValid()) continue; SourceLocation B = Info.getRange(i).getBegin(); SourceLocation E = Info.getRange(i).getEnd(); B = SM.getInstantiationLoc(B); E = SM.getInstantiationLoc(E); // If the End location and the start location are the same and are a // macro location, then the range was something that came from a macro // expansion or _Pragma. If this is an object-like macro, the best we // can do is to highlight the range. If this is a function-like // macro, we'd also like to highlight the arguments. if (B == E && Info.getRange(i).getEnd().isMacroID()) E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); // If the start or end of the range is in another file, just discard // it. if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) continue; // Add in the length of the token, so that we cover multi-char tokens. unsigned TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' << SM.getLineNumber(EInfo.first, EInfo.second) << ':' << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}'; PrintedRange = true; } if (PrintedRange) OS << ':'; } OS << ' '; if (DiagOpts->ShowColors) OS.resetColor(); } } if (DiagOpts->ShowColors) { // Print diagnostic category in bold and color switch (Level) { case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); case Diagnostic::Note: OS.changeColor(noteColor, true); break; case Diagnostic::Warning: OS.changeColor(warningColor, true); break; case Diagnostic::Error: OS.changeColor(errorColor, true); break; case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; } } switch (Level) { case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); case Diagnostic::Note: OS << "note: "; break; case Diagnostic::Warning: OS << "warning: "; break; case Diagnostic::Error: OS << "error: "; break; case Diagnostic::Fatal: OS << "fatal error: "; break; } if (DiagOpts->ShowColors) OS.resetColor(); llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); if (DiagOpts->ShowOptionNames) { if (const char *Opt = Diagnostic::getWarningOptionForDiag(Info.getID())) { OutStr += " [-W"; OutStr += Opt; OutStr += ']'; } else if (Diagnostic::isBuiltinExtensionDiag(Info.getID())) { OutStr += " [-pedantic]"; } } if (DiagOpts->ShowColors) { // Print warnings, errors and fatal errors in bold, no color switch (Level) { case Diagnostic::Warning: OS.changeColor(savedColor, true); break; case Diagnostic::Error: OS.changeColor(savedColor, true); break; case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; default: break; //don't bold notes } } if (DiagOpts->MessageLength) { // We will be word-wrapping the error message, so compute the // column number where we currently are (after printing the // location information). unsigned Column = OS.tell() - StartOfLocationInfo; PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); } else { OS.write(OutStr.begin(), OutStr.size()); } OS << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); // If caret diagnostics are enabled and we have location, we want to // emit the caret. However, we only do this if the location moved // from the last diagnostic, if the last diagnostic was a note that // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. if (DiagOpts->ShowCarets && Info.getLocation().isValid() && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || Info.getNumCodeModificationHints())) { // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. LastLoc = Info.getLocation(); LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); // Get the ranges into a local array we can hack on. SourceRange Ranges[20]; unsigned NumRanges = Info.getNumRanges(); assert(NumRanges < 20 && "Out of space"); for (unsigned i = 0; i != NumRanges; ++i) Ranges[i] = Info.getRange(i); unsigned NumHints = Info.getNumCodeModificationHints(); for (unsigned idx = 0; idx < NumHints; ++idx) { const CodeModificationHint &Hint = Info.getCodeModificationHint(idx); if (Hint.RemoveRange.isValid()) { assert(NumRanges < 20 && "Out of space"); Ranges[NumRanges++] = Hint.RemoveRange; } } EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), Info.getCodeModificationHints(), Info.getNumCodeModificationHints(), DiagOpts->MessageLength); } OS.flush(); }
void TextDiagnosticPrinter::EmitCaretDiagnostic(SourceLocation Loc, SourceRange *Ranges, unsigned NumRanges, SourceManager &SM, const CodeModificationHint *Hints, unsigned NumHints, unsigned Columns) { assert(LangOpts && "Unexpected diagnostic outside source file processing"); assert(!Loc.isInvalid() && "must have a valid source location here"); // If this is a macro ID, first emit information about where this was // instantiated (recursively) then emit information about where the token was // spelled from. if (!Loc.isFileID()) { SourceLocation OneLevelUp = SM.getImmediateInstantiationRange(Loc).first; // FIXME: Map ranges? EmitCaretDiagnostic(OneLevelUp, Ranges, NumRanges, SM, 0, 0, Columns); // Map the location. Loc = SM.getImmediateSpellingLoc(Loc); // Map the ranges. for (unsigned i = 0; i != NumRanges; ++i) { SourceLocation S = Ranges[i].getBegin(), E = Ranges[i].getEnd(); if (S.isMacroID()) S = SM.getImmediateSpellingLoc(S); if (E.isMacroID()) E = SM.getImmediateSpellingLoc(E); Ranges[i] = SourceRange(S, E); } // Get the pretty name, according to #line directives etc. PresumedLoc PLoc = SM.getPresumedLoc(Loc); // If this diagnostic is not in the main file, print out the "included from" // lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { LastWarningLoc = PLoc.getIncludeLoc(); PrintIncludeStack(LastWarningLoc, SM); } if (DiagOpts->ShowLocation) { // Emit the file/line/column that this expansion came from. OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':'; if (DiagOpts->ShowColumn) OS << PLoc.getColumn() << ':'; OS << ' '; } OS << "note: instantiated from:\n"; EmitCaretDiagnostic(Loc, Ranges, NumRanges, SM, Hints, NumHints, Columns); return; } // Decompose the location into a FID/Offset pair. std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc); FileID FID = LocInfo.first; unsigned FileOffset = LocInfo.second; // Get information about the buffer it points into. std::pair<const char*, const char*> BufferInfo = SM.getBufferData(FID); const char *BufStart = BufferInfo.first; unsigned ColNo = SM.getColumnNumber(FID, FileOffset); unsigned CaretEndColNo = ColNo + Lexer::MeasureTokenLength(Loc, SM, *LangOpts); // Rewind from the current position to the start of the line. const char *TokPtr = BufStart+FileOffset; const char *LineStart = TokPtr-ColNo+1; // Column # is 1-based. // Compute the line end. Scan forward from the error position to the end of // the line. const char *LineEnd = TokPtr; while (*LineEnd != '\n' && *LineEnd != '\r' && *LineEnd != '\0') ++LineEnd; // FIXME: This shouldn't be necessary, but the CaretEndColNo can extend past // the source line length as currently being computed. See // test/Misc/message-length.c. CaretEndColNo = std::min(CaretEndColNo, unsigned(LineEnd - LineStart)); // Copy the line of code into an std::string for ease of manipulation. std::string SourceLine(LineStart, LineEnd); // Create a line for the caret that is filled with spaces that is the same // length as the line of source code. std::string CaretLine(LineEnd-LineStart, ' '); // Highlight all of the characters covered by Ranges with ~ characters. if (NumRanges) { unsigned LineNo = SM.getLineNumber(FID, FileOffset); for (unsigned i = 0, e = NumRanges; i != e; ++i) HighlightRange(Ranges[i], SM, LineNo, FID, CaretLine, SourceLine); } // Next, insert the caret itself. if (ColNo-1 < CaretLine.size()) CaretLine[ColNo-1] = '^'; else CaretLine.push_back('^'); // Scan the source line, looking for tabs. If we find any, manually expand // them to spaces and update the CaretLine to match. for (unsigned i = 0; i != SourceLine.size(); ++i) { if (SourceLine[i] != '\t') continue; // Replace this tab with at least one space. SourceLine[i] = ' '; // Compute the number of spaces we need to insert. unsigned TabStop = DiagOpts->TabStop; assert(0 < TabStop && TabStop <= DiagnosticOptions::MaxTabStop && "Invalid -ftabstop value"); unsigned NumSpaces = ((i+TabStop)/TabStop * TabStop) - (i+1); assert(NumSpaces < TabStop && "Invalid computation of space amt"); // Insert spaces into the SourceLine. SourceLine.insert(i+1, NumSpaces, ' '); // Insert spaces or ~'s into CaretLine. CaretLine.insert(i+1, NumSpaces, CaretLine[i] == '~' ? '~' : ' '); } // If we are in -fdiagnostics-print-source-range-info mode, we are trying to // produce easily machine parsable output. Add a space before the source line // and the caret to make it trivial to tell the main diagnostic line from what // the user is intended to see. if (DiagOpts->ShowSourceRanges) { SourceLine = ' ' + SourceLine; CaretLine = ' ' + CaretLine; } std::string FixItInsertionLine; if (NumHints && DiagOpts->ShowFixits) { for (const CodeModificationHint *Hint = Hints, *LastHint = Hints + NumHints; Hint != LastHint; ++Hint) { if (Hint->InsertionLoc.isValid()) { // We have an insertion hint. Determine whether the inserted // code is on the same line as the caret. std::pair<FileID, unsigned> HintLocInfo = SM.getDecomposedInstantiationLoc(Hint->InsertionLoc); if (SM.getLineNumber(HintLocInfo.first, HintLocInfo.second) == SM.getLineNumber(FID, FileOffset)) { // Insert the new code into the line just below the code // that the user wrote. unsigned HintColNo = SM.getColumnNumber(HintLocInfo.first, HintLocInfo.second); unsigned LastColumnModified = HintColNo - 1 + Hint->CodeToInsert.size(); if (LastColumnModified > FixItInsertionLine.size()) FixItInsertionLine.resize(LastColumnModified, ' '); std::copy(Hint->CodeToInsert.begin(), Hint->CodeToInsert.end(), FixItInsertionLine.begin() + HintColNo - 1); } else { FixItInsertionLine.clear(); break; } } } // Now that we have the entire fixit line, expand the tabs in it. // Since we don't want to insert spaces in the middle of a word, // find each word and the column it should line up with and insert // spaces until they match. if (!FixItInsertionLine.empty()) { unsigned FixItPos = 0; unsigned LinePos = 0; unsigned TabExpandedCol = 0; unsigned LineLength = LineEnd - LineStart; while (FixItPos < FixItInsertionLine.size() && LinePos < LineLength) { // Find the next word in the FixIt line. while (FixItPos < FixItInsertionLine.size() && FixItInsertionLine[FixItPos] == ' ') ++FixItPos; unsigned CharDistance = FixItPos - TabExpandedCol; // Walk forward in the source line, keeping track of // the tab-expanded column. for (unsigned I = 0; I < CharDistance; ++I, ++LinePos) if (LinePos >= LineLength || LineStart[LinePos] != '\t') ++TabExpandedCol; else TabExpandedCol = (TabExpandedCol/DiagOpts->TabStop + 1) * DiagOpts->TabStop; // Adjust the fixit line to match this column. FixItInsertionLine.insert(FixItPos, TabExpandedCol-FixItPos, ' '); FixItPos = TabExpandedCol; // Walk to the end of the word. while (FixItPos < FixItInsertionLine.size() && FixItInsertionLine[FixItPos] != ' ') ++FixItPos; } } } // If the source line is too long for our terminal, select only the // "interesting" source region within that line. if (Columns && SourceLine.size() > Columns) SelectInterestingSourceRegion(SourceLine, CaretLine, FixItInsertionLine, CaretEndColNo, Columns); // Finally, remove any blank spaces from the end of CaretLine. while (CaretLine[CaretLine.size()-1] == ' ') CaretLine.erase(CaretLine.end()-1); // Emit what we have computed. OS << SourceLine << '\n'; if (DiagOpts->ShowColors) OS.changeColor(caretColor, true); OS << CaretLine << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); if (!FixItInsertionLine.empty()) { if (DiagOpts->ShowColors) // Print fixit line in color OS.changeColor(fixitColor, false); if (DiagOpts->ShowSourceRanges) OS << ' '; OS << FixItInsertionLine << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); } }
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Figure out which token this is. IdentifierInfo *II = Tok.getIdentifierInfo(); assert(II && "Can't be a macro without id info!"); // If this is an _Pragma or Microsoft __pragma directive, expand it, // invoke the pragma handler, then lex the token after it. if (II == Ident_Pragma) return Handle_Pragma(Tok); else if (II == Ident__pragma) // in non-MS mode this is null return HandleMicrosoft__pragma(Tok); ++NumBuiltinMacroExpanded; llvm::SmallString<128> TmpBuffer; llvm::raw_svector_ostream OS(TmpBuffer); // Set up the return result. Tok.setIdentifierInfo(0); Tok.clearFlag(Token::NeedsCleaning); if (II == Ident__LINE__) { // C99 6.10.8: "__LINE__: The presumed line number (within the current // source file) of the current source line (an integer constant)". This can // be affected by #line. SourceLocation Loc = Tok.getLocation(); // Advance to the location of the first _, this might not be the first byte // of the token if it starts with an escaped newline. Loc = AdvanceToTokenCharacter(Loc, 0); // One wrinkle here is that GCC expands __LINE__ to location of the *end* of // a macro instantiation. This doesn't matter for object-like macros, but // can matter for a function-like macro that expands to contain __LINE__. // Skip down through instantiation points until we find a file loc for the // end of the instantiation history. Loc = SourceMgr.getInstantiationRange(Loc).second; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); // __LINE__ expands to a simple numeric value. OS << PLoc.getLine(); Tok.setKind(tok::numeric_constant); } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { // C99 6.10.8: "__FILE__: The presumed name of the current source file (a // character string literal)". This can be affected by #line. PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); // __BASE_FILE__ is a GNU extension that returns the top of the presumed // #include stack instead of the current file. if (II == Ident__BASE_FILE__) { SourceLocation NextLoc = PLoc.getIncludeLoc(); while (NextLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(NextLoc); NextLoc = PLoc.getIncludeLoc(); } } // Escape this filename. Turn '\' -> '\\' '"' -> '\"' llvm::SmallString<128> FN; FN += PLoc.getFilename(); Lexer::Stringify(FN); OS << '"' << FN.str() << '"'; Tok.setKind(tok::string_literal); } else if (II == Ident__DATE__) { if (!DATELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"Mmm dd yyyy\"")); Tok.setLocation(SourceMgr.createInstantiationLoc(DATELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__TIME__) { if (!TIMELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"hh:mm:ss\"")); Tok.setLocation(SourceMgr.createInstantiationLoc(TIMELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__INCLUDE_LEVEL__) { // Compute the presumed include depth of this token. This can be affected // by GNU line markers. unsigned Depth = 0; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); for (; PLoc.isValid(); ++Depth) PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); // __INCLUDE_LEVEL__ expands to a simple numeric value. OS << Depth; Tok.setKind(tok::numeric_constant); } else if (II == Ident__TIMESTAMP__) { // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. // Get the file that we are lexing out of. If we're currently lexing from // a macro, dig into the include stack. const FileEntry *CurFile = 0; PreprocessorLexer *TheLexer = getCurrentFileLexer(); if (TheLexer) CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); const char *Result; if (CurFile) { time_t TT = CurFile->getModificationTime(); struct tm *TM = localtime(&TT); Result = asctime(TM); } else { Result = "??? ??? ?? ??:??:?? ????\n"; } // Surround the string with " and strip the trailing newline. OS << '"' << llvm::StringRef(Result, strlen(Result)-1) << '"'; Tok.setKind(tok::string_literal); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_feature || II == Ident__has_builtin) { // The argument to these two builtins should be a parenthesized identifier. SourceLocation StartLoc = Tok.getLocation(); bool IsValid = false; IdentifierInfo *FeatureII = 0; // Read the '('. Lex(Tok); if (Tok.is(tok::l_paren)) { // Read the identifier Lex(Tok); if (Tok.is(tok::identifier)) { FeatureII = Tok.getIdentifierInfo(); // Read the ')'. Lex(Tok); if (Tok.is(tok::r_paren)) IsValid = true; } } bool Value = false; if (!IsValid) Diag(StartLoc, diag::err_feature_check_malformed); else if (II == Ident__has_builtin) { // Check for a builtin is trivial. Value = FeatureII->getBuiltinID() != 0; } else { assert(II == Ident__has_feature && "Must be feature check"); Value = HasFeature(*this, FeatureII); } OS << (int)Value; Tok.setKind(tok::numeric_constant); } else if (II == Ident__has_include || II == Ident__has_include_next) { // The argument to these two builtins should be a parenthesized // file name string literal using angle brackets (<>) or // double-quotes (""). bool Value = false; bool IsValid; if (II == Ident__has_include) IsValid = EvaluateHasInclude(Value, Tok, II, *this); else IsValid = EvaluateHasIncludeNext(Value, Tok, II, *this); OS << (int)Value; Tok.setKind(tok::numeric_constant); } else { assert(0 && "Unknown identifier!"); } CreateString(OS.str().data(), OS.str().size(), Tok, Tok.getLocation()); }
void TextDiagnosticPrinter::HandleDiagnostic(Diagnostic::Level Level, const DiagnosticInfo &Info) { // Default implementation (Warnings/errors count). DiagnosticClient::HandleDiagnostic(Level, Info); // Keeps track of the the starting position of the location // information (e.g., "foo.c:10:4:") that precedes the error // message. We use this information to determine how long the // file+line+column number prefix is. uint64_t StartOfLocationInfo = OS.tell(); if (!Prefix.empty()) OS << Prefix << ": "; // If the location is specified, print out a file/line/col and include trace // if enabled. if (Info.getLocation().isValid()) { const SourceManager &SM = Info.getSourceManager(); PresumedLoc PLoc = getDiagnosticPresumedLoc(SM, Info.getLocation()); if (PLoc.isInvalid()) { // At least print the file name if available: FileID FID = SM.getFileID(Info.getLocation()); if (!FID.isInvalid()) { const FileEntry* FE = SM.getFileEntryForID(FID); if (FE && FE->getName()) { OS << FE->getName(); if (FE->getDevice() == 0 && FE->getInode() == 0 && FE->getFileMode() == 0) { // in PCH is a guess, but a good one: OS << " (in PCH)"; } OS << ": "; } } } else { unsigned LineNo = PLoc.getLine(); // First, if this diagnostic is not in the main file, print out the // "included from" lines. if (LastWarningLoc != PLoc.getIncludeLoc()) { LastWarningLoc = PLoc.getIncludeLoc(); PrintIncludeStack(Level, LastWarningLoc, SM); StartOfLocationInfo = OS.tell(); } // Compute the column number. if (DiagOpts->ShowLocation) { if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); OS << PLoc.getFilename(); switch (DiagOpts->Format) { case DiagnosticOptions::Clang: OS << ':' << LineNo; break; case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; case DiagnosticOptions::Vi: OS << " +" << LineNo; break; } if (DiagOpts->ShowColumn) if (unsigned ColNo = PLoc.getColumn()) { if (DiagOpts->Format == DiagnosticOptions::Msvc) { OS << ','; ColNo--; } else OS << ':'; OS << ColNo; } switch (DiagOpts->Format) { case DiagnosticOptions::Clang: case DiagnosticOptions::Vi: OS << ':'; break; case DiagnosticOptions::Msvc: OS << ") : "; break; } if (DiagOpts->ShowSourceRanges && Info.getNumRanges()) { FileID CaretFileID = SM.getFileID(SM.getInstantiationLoc(Info.getLocation())); bool PrintedRange = false; for (unsigned i = 0, e = Info.getNumRanges(); i != e; ++i) { // Ignore invalid ranges. if (!Info.getRange(i).isValid()) continue; SourceLocation B = Info.getRange(i).getBegin(); SourceLocation E = Info.getRange(i).getEnd(); B = SM.getInstantiationLoc(B); E = SM.getInstantiationLoc(E); // If the End location and the start location are the same and are a // macro location, then the range was something that came from a // macro expansion or _Pragma. If this is an object-like macro, the // best we can do is to highlight the range. If this is a // function-like macro, we'd also like to highlight the arguments. if (B == E && Info.getRange(i).getEnd().isMacroID()) E = SM.getInstantiationRange(Info.getRange(i).getEnd()).second; std::pair<FileID, unsigned> BInfo = SM.getDecomposedLoc(B); std::pair<FileID, unsigned> EInfo = SM.getDecomposedLoc(E); // If the start or end of the range is in another file, just discard // it. if (BInfo.first != CaretFileID || EInfo.first != CaretFileID) continue; // Add in the length of the token, so that we cover multi-char // tokens. unsigned TokSize = 0; if (Info.getRange(i).isTokenRange()) TokSize = Lexer::MeasureTokenLength(E, SM, *LangOpts); OS << '{' << SM.getLineNumber(BInfo.first, BInfo.second) << ':' << SM.getColumnNumber(BInfo.first, BInfo.second) << '-' << SM.getLineNumber(EInfo.first, EInfo.second) << ':' << (SM.getColumnNumber(EInfo.first, EInfo.second)+TokSize) << '}'; PrintedRange = true; } if (PrintedRange) OS << ':'; } } OS << ' '; if (DiagOpts->ShowColors) OS.resetColor(); } } if (DiagOpts->ShowColors) { // Print diagnostic category in bold and color switch (Level) { case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); case Diagnostic::Note: OS.changeColor(noteColor, true); break; case Diagnostic::Warning: OS.changeColor(warningColor, true); break; case Diagnostic::Error: OS.changeColor(errorColor, true); break; case Diagnostic::Fatal: OS.changeColor(fatalColor, true); break; } } switch (Level) { case Diagnostic::Ignored: assert(0 && "Invalid diagnostic type"); case Diagnostic::Note: OS << "note: "; break; case Diagnostic::Warning: OS << "warning: "; break; case Diagnostic::Error: OS << "error: "; break; case Diagnostic::Fatal: OS << "fatal error: "; break; } if (DiagOpts->ShowColors) OS.resetColor(); llvm::SmallString<100> OutStr; Info.FormatDiagnostic(OutStr); if (DiagOpts->ShowNames && !DiagnosticIDs::isBuiltinNote(Info.getID())) { OutStr += " ["; OutStr += DiagnosticIDs::getName(Info.getID()); OutStr += "]"; } std::string OptionName; if (DiagOpts->ShowOptionNames) { // Was this a warning mapped to an error using -Werror or pragma? if (Level == Diagnostic::Error && DiagnosticIDs::isBuiltinWarningOrExtension(Info.getID())) { diag::Mapping mapping = diag::MAP_IGNORE; Info.getDiags()->getDiagnosticLevel(Info.getID(), Info.getLocation(), &mapping); if (mapping == diag::MAP_WARNING) OptionName += "-Werror"; } llvm::StringRef Opt = DiagnosticIDs::getWarningOptionForDiag(Info.getID()); if (!Opt.empty()) { if (!OptionName.empty()) OptionName += ','; OptionName += "-W"; OptionName += Opt; } else if (Info.getID() == diag::fatal_too_many_errors) { OptionName = "-ferror-limit="; } else { // If the diagnostic is an extension diagnostic and not enabled by default // then it must have been turned on with -pedantic. bool EnabledByDefault; if (DiagnosticIDs::isBuiltinExtensionDiag(Info.getID(), EnabledByDefault) && !EnabledByDefault) OptionName = "-pedantic"; } } // If the user wants to see category information, include it too. unsigned DiagCategory = 0; if (DiagOpts->ShowCategories) DiagCategory = DiagnosticIDs::getCategoryNumberForDiag(Info.getID()); // If there is any categorization information, include it. if (!OptionName.empty() || DiagCategory != 0) { bool NeedsComma = false; OutStr += " ["; if (!OptionName.empty()) { OutStr += OptionName; NeedsComma = true; } if (DiagCategory) { if (NeedsComma) OutStr += ','; if (DiagOpts->ShowCategories == 1) OutStr += llvm::utostr(DiagCategory); else { assert(DiagOpts->ShowCategories == 2 && "Invalid ShowCategories value"); OutStr += DiagnosticIDs::getCategoryNameFromID(DiagCategory); } } OutStr += "]"; } if (DiagOpts->ShowColors) { // Print warnings, errors and fatal errors in bold, no color switch (Level) { case Diagnostic::Warning: OS.changeColor(savedColor, true); break; case Diagnostic::Error: OS.changeColor(savedColor, true); break; case Diagnostic::Fatal: OS.changeColor(savedColor, true); break; default: break; //don't bold notes } } if (DiagOpts->MessageLength) { // We will be word-wrapping the error message, so compute the // column number where we currently are (after printing the // location information). unsigned Column = OS.tell() - StartOfLocationInfo; PrintWordWrapped(OS, OutStr, DiagOpts->MessageLength, Column); } else { OS.write(OutStr.begin(), OutStr.size()); } OS << '\n'; if (DiagOpts->ShowColors) OS.resetColor(); // If caret diagnostics are enabled and we have location, we want to // emit the caret. However, we only do this if the location moved // from the last diagnostic, if the last diagnostic was a note that // was part of a different warning or error diagnostic, or if the // diagnostic has ranges. We don't want to emit the same caret // multiple times if one loc has multiple diagnostics. if (DiagOpts->ShowCarets && Info.getLocation().isValid() && ((LastLoc != Info.getLocation()) || Info.getNumRanges() || (LastCaretDiagnosticWasNote && Level != Diagnostic::Note) || Info.getNumFixItHints())) { // Cache the LastLoc, it allows us to omit duplicate source/caret spewage. LastLoc = FullSourceLoc(Info.getLocation(), Info.getSourceManager()); LastCaretDiagnosticWasNote = (Level == Diagnostic::Note); // Get the ranges into a local array we can hack on. CharSourceRange Ranges[20]; unsigned NumRanges = Info.getNumRanges(); assert(NumRanges < 20 && "Out of space"); for (unsigned i = 0; i != NumRanges; ++i) Ranges[i] = Info.getRange(i); unsigned NumHints = Info.getNumFixItHints(); for (unsigned i = 0; i != NumHints; ++i) { const FixItHint &Hint = Info.getFixItHint(i); if (Hint.RemoveRange.isValid()) { assert(NumRanges < 20 && "Out of space"); Ranges[NumRanges++] = Hint.RemoveRange; } } const SourceManager &SM = LastLoc.getManager(); unsigned MacroInstSkipStart = 0, MacroInstSkipEnd = 0; if (DiagOpts && DiagOpts->MacroBacktraceLimit && !LastLoc.isFileID()) { // Compute the length of the macro-expansion backtrace, so that we // can establish which steps in the macro backtrace we'll skip. SourceLocation Loc = LastLoc; unsigned Depth = 0; do { ++Depth; Loc = skipToMacroArgExpansion(SM, Loc); Loc = getImmediateMacroCallerLoc(SM, Loc); } while (!Loc.isFileID()); if (Depth > DiagOpts->MacroBacktraceLimit) { MacroInstSkipStart = DiagOpts->MacroBacktraceLimit / 2 + DiagOpts->MacroBacktraceLimit % 2; MacroInstSkipEnd = Depth - DiagOpts->MacroBacktraceLimit / 2; } } EmitCaretDiagnostic(LastLoc, Ranges, NumRanges, LastLoc.getManager(), Info.getFixItHints(), Info.getNumFixItHints(), DiagOpts->MessageLength, 0, MacroInstSkipStart, MacroInstSkipEnd); } OS.flush(); }
/// ExpandBuiltinMacro - If an identifier token is read that is to be expanded /// as a builtin macro, handle it and return the next token as 'Tok'. void Preprocessor::ExpandBuiltinMacro(Token &Tok) { // Figure out which token this is. IdentifierInfo *II = Tok.getIdentifierInfo(); assert(II && "Can't be a macro without id info!"); ++NumBuiltinMacroExpanded; SmallString<128> TmpBuffer; llvm::raw_svector_ostream OS(TmpBuffer); // Set up the return result. Tok.setIdentifierInfo(nullptr); Tok.clearFlag(Token::NeedsCleaning); if (II == Ident__LINE__) { // C99 6.10.8: "__LINE__: The presumed line number (within the current // source file) of the current source line (an integer constant)". This can // be affected by #line. SourceLocation Loc = Tok.getLocation(); // Advance to the location of the first _, this might not be the first byte // of the token if it starts with an escaped newline. Loc = AdvanceToTokenCharacter(Loc, 0); // One wrinkle here is that GCC expands __LINE__ to location of the *end* of // a macro expansion. This doesn't matter for object-like macros, but // can matter for a function-like macro that expands to contain __LINE__. // Skip down through expansion points until we find a file loc for the // end of the expansion history. Loc = SourceMgr.getExpansionRange(Loc).getEnd(); PresumedLoc PLoc = SourceMgr.getPresumedLoc(Loc); // __LINE__ expands to a simple numeric value. OS << (PLoc.isValid()? PLoc.getLine() : 1); Tok.setKind(tok::numeric_constant); } else if (II == Ident__FILE__ || II == Ident__BASE_FILE__) { // C99 6.10.8: "__FILE__: The presumed name of the current source file (a // character string literal)". This can be affected by #line. PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); // __BASE_FILE__ is a GNU extension that returns the top of the presumed // #include stack instead of the current file. if (II == Ident__BASE_FILE__ && PLoc.isValid()) { SourceLocation NextLoc = PLoc.getIncludeLoc(); while (NextLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(NextLoc); if (PLoc.isInvalid()) break; NextLoc = PLoc.getIncludeLoc(); } } // Escape this filename. Turn '\' -> '\\' '"' -> '\"' SmallString<128> FN; if (PLoc.isValid()) { FN += PLoc.getFilename(); Lexer::Stringify(FN); OS << '"' << FN << '"'; } Tok.setKind(tok::string_literal); } else if (II == Ident__DATE__) { Diag(Tok.getLocation(), diag::warn_pp_date_time); if (!DATELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"Mmm dd yyyy\"")); Tok.setLocation(SourceMgr.createExpansionLoc(DATELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__TIME__) { Diag(Tok.getLocation(), diag::warn_pp_date_time); if (!TIMELoc.isValid()) ComputeDATE_TIME(DATELoc, TIMELoc, *this); Tok.setKind(tok::string_literal); Tok.setLength(strlen("\"hh:mm:ss\"")); Tok.setLocation(SourceMgr.createExpansionLoc(TIMELoc, Tok.getLocation(), Tok.getLocation(), Tok.getLength())); return; } else if (II == Ident__INCLUDE_LEVEL__) { // Compute the presumed include depth of this token. This can be affected // by GNU line markers. unsigned Depth = 0; PresumedLoc PLoc = SourceMgr.getPresumedLoc(Tok.getLocation()); if (PLoc.isValid()) { PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); for (; PLoc.isValid(); ++Depth) PLoc = SourceMgr.getPresumedLoc(PLoc.getIncludeLoc()); } // __INCLUDE_LEVEL__ expands to a simple numeric value. OS << Depth; Tok.setKind(tok::numeric_constant); } else if (II == Ident__TIMESTAMP__) { Diag(Tok.getLocation(), diag::warn_pp_date_time); // MSVC, ICC, GCC, VisualAge C++ extension. The generated string should be // of the form "Ddd Mmm dd hh::mm::ss yyyy", which is returned by asctime. // Get the file that we are lexing out of. If we're currently lexing from // a macro, dig into the include stack. const FileEntry *CurFile = nullptr; PreprocessorLexer *TheLexer = getCurrentFileLexer(); if (TheLexer) CurFile = SourceMgr.getFileEntryForID(TheLexer->getFileID()); const char *Result; if (CurFile) { time_t TT = CurFile->getModificationTime(); struct tm *TM = localtime(&TT); Result = asctime(TM); } else { Result = "??? ??? ?? ??:??:?? ????\n"; } // Surround the string with " and strip the trailing newline. OS << '"' << StringRef(Result).drop_back() << '"'; Tok.setKind(tok::string_literal); } else if (II == Ident__COUNTER__) { // __COUNTER__ expands to a simple numeric value. OS << CounterValue++; Tok.setKind(tok::numeric_constant); } else if (II == Ident__identifier) { SourceLocation Loc = Tok.getLocation(); // We're expecting '__identifier' '(' identifier ')'. Try to recover // if the parens are missing. LexNonComment(Tok); if (Tok.isNot(tok::l_paren)) { // No '(', use end of last token. Diag(getLocForEndOfToken(Loc), diag::err_pp_expected_after) << II << tok::l_paren; // If the next token isn't valid as our argument, we can't recover. if (Tok.getIdentifierInfo()) Tok.setKind(tok::identifier); return; } SourceLocation LParenLoc = Tok.getLocation(); LexNonComment(Tok); if (Tok.getIdentifierInfo()) Tok.setKind(tok::identifier); else { Diag(Tok.getLocation(), diag::err_pp_identifier_arg_not_identifier) << Tok.getKind(); // Don't walk past anything that's not a real token. if (Tok.isOneOf(tok::eof, tok::eod)) return; } // Discard the ')', preserving 'Tok' as our result. Token RParen; LexNonComment(RParen); if (RParen.isNot(tok::r_paren)) { Diag(getLocForEndOfToken(Tok.getLocation()), diag::err_pp_expected_after) << Tok.getKind() << tok::r_paren; Diag(LParenLoc, diag::note_matching) << tok::l_paren; } return; } else { llvm_unreachable("Unknown identifier!"); } CreateString(OS.str(), Tok, Tok.getLocation(), Tok.getLocation()); }