void TextDiagnostic::emitImportLocation(SourceLocation Loc, PresumedLoc PLoc, StringRef ModuleName, const SourceManager &SM) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "In module '" << ModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "In module '" << ModuleName << "':\n"; }
static void printSourceLocation(SourceLocation loc, ASTContext &Ctx, raw_ostream &OS) { SourceManager &SM = Ctx.getSourceManager(); PresumedLoc PL = SM.getPresumedLoc(loc); OS << llvm::sys::path::filename(PL.getFilename()); OS << ":" << PL.getLine() << ":" << PL.getColumn(); }
void TextDiagnostic::emitBuildingModuleLocation(FullSourceLoc Loc, PresumedLoc PLoc, StringRef ModuleName) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "While building module '" << ModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "While building module '" << ModuleName << "':\n"; }
void TextDiagnostic::emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM) { if (DiagOpts->ShowLocation && PLoc.isValid()) OS << "In file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "In included file:\n"; }
void TextDiagnostic::emitBuildingPCModuleLocation(SourceLocation Loc, PresumedLoc PLoc, StringRef PCModuleName, const SourceManager &SM) { if (DiagOpts->ShowLocation && PLoc.getFilename()) OS << "While building module '" << PCModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":\n"; else OS << "While building module '" << PCModuleName << "':\n"; }
void DiagnosticNoteRenderer::emitIncludeLocation(SourceLocation Loc, PresumedLoc PLoc, const SourceManager &SM) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); Message << "in file included from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; emitNote(Loc, Message.str(), &SM); }
llvm::Value *CGOpenMPRuntime::EmitOpenMPUpdateLocation( CodeGenFunction &CGF, SourceLocation Loc, OpenMPLocationFlags Flags) { // If no debug info is generated - return global default location. if (CGM.getCodeGenOpts().getDebugInfo() == CodeGenOptions::NoDebugInfo || Loc.isInvalid()) return GetOrCreateDefaultOpenMPLocation(Flags); assert(CGF.CurFn && "No function in current CodeGenFunction."); llvm::Value *LocValue = nullptr; auto I = OpenMPLocThreadIDMap.find(CGF.CurFn); if (I != OpenMPLocThreadIDMap.end()) LocValue = I->second.DebugLoc; // OpenMPLocThreadIDMap may have null DebugLoc and non-null ThreadID, if // GetOpenMPThreadID was called before this routine. if (LocValue == nullptr) { // Generate "ident_t .kmpc_loc.addr;" llvm::AllocaInst *AI = CGF.CreateTempAlloca(IdentTy, ".kmpc_loc.addr"); AI->setAlignment(CGM.getDataLayout().getPrefTypeAlignment(IdentTy)); auto &Elem = OpenMPLocThreadIDMap.FindAndConstruct(CGF.CurFn); Elem.second.DebugLoc = AI; LocValue = AI; CGBuilderTy::InsertPointGuard IPG(CGF.Builder); CGF.Builder.SetInsertPoint(CGF.AllocaInsertPt); CGF.Builder.CreateMemCpy(LocValue, GetOrCreateDefaultOpenMPLocation(Flags), llvm::ConstantExpr::getSizeOf(IdentTy), CGM.PointerAlignInBytes); } // char **psource = &.kmpc_loc_<flags>.addr.psource; auto *PSource = CGF.Builder.CreateConstInBoundsGEP2_32(LocValue, 0, IdentField_PSource); auto OMPDebugLoc = OpenMPDebugLocMap.lookup(Loc.getRawEncoding()); if (OMPDebugLoc == nullptr) { SmallString<128> Buffer2; llvm::raw_svector_ostream OS2(Buffer2); // Build debug location PresumedLoc PLoc = CGF.getContext().getSourceManager().getPresumedLoc(Loc); OS2 << ";" << PLoc.getFilename() << ";"; if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CGF.CurFuncDecl)) { OS2 << FD->getQualifiedNameAsString(); } OS2 << ";" << PLoc.getLine() << ";" << PLoc.getColumn() << ";;"; OMPDebugLoc = CGF.Builder.CreateGlobalStringPtr(OS2.str()); OpenMPDebugLocMap[Loc.getRawEncoding()] = OMPDebugLoc; } // *psource = ";<File>;<Function>;<Line>;<Column>;;"; CGF.Builder.CreateStore(OMPDebugLoc, PSource); return LocValue; }
static void printSourceRange(CharSourceRange range, ASTContext &Ctx, raw_ostream &OS) { SourceManager &SM = Ctx.getSourceManager(); const LangOptions &langOpts = Ctx.getLangOpts(); PresumedLoc PL = SM.getPresumedLoc(range.getBegin()); OS << llvm::sys::path::filename(PL.getFilename()); OS << " [" << PL.getLine() << ":" << PL.getColumn(); OS << " - "; SourceLocation end = range.getEnd(); PL = SM.getPresumedLoc(end); unsigned endCol = PL.getColumn() - 1; if (!range.isTokenRange()) endCol += Lexer::MeasureTokenLength(end, SM, langOpts); OS << PL.getLine() << ":" << endCol << "]"; }
foreign_t pl_getPresumedLoc(term_t DeclT, term_t FilenameT, term_t LineT, term_t ColT) { const Decl *D; if ( !PL_get_pointer(DeclT, (void **) &D)) return PL_warning("getPresumedLoc/4: instantiation fault on first arg"); const SourceManager &SM = getCompilationInfo()->getSourceManager(); const PresumedLoc PL = SM.getPresumedLoc(D->getLocation()); if ( !PL_unify_atom_chars(FilenameT, PL.getFilename())) return FALSE; if ( !PL_unify_int64(LineT, (int64_t) PL.getLine())) return FALSE; return PL_unify_int64(ColT, (int64_t) PL.getColumn()); }
std::string BlinkGCPluginConsumer::GetLocString(SourceLocation loc) { const SourceManager& source_manager = instance_.getSourceManager(); PresumedLoc ploc = source_manager.getPresumedLoc(loc); if (ploc.isInvalid()) return ""; std::string loc_str; llvm::raw_string_ostream os(loc_str); os << ploc.getFilename() << ":" << ploc.getLine() << ":" << ploc.getColumn(); return os.str(); }
void DiagnosticNoteRenderer::emitBuildingModuleLocation(SourceLocation Loc, PresumedLoc PLoc, StringRef ModuleName, const SourceManager &SM) { // Generate a note indicating the include location. SmallString<200> MessageStorage; llvm::raw_svector_ostream Message(MessageStorage); Message << "while building module '" << ModuleName << "' imported from " << PLoc.getFilename() << ':' << PLoc.getLine() << ":"; emitNote(Loc, Message.str(), &SM); }
llvm::MDNode *SanitizerMetadata::getLocationMetadata(SourceLocation Loc) { PresumedLoc PLoc = CGM.getContext().getSourceManager().getPresumedLoc(Loc); if (!PLoc.isValid()) return nullptr; llvm::LLVMContext &VMContext = CGM.getLLVMContext(); llvm::Value *LocMetadata[] = { llvm::MDString::get(VMContext, PLoc.getFilename()), llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), PLoc.getLine()), llvm::ConstantInt::get(llvm::Type::getInt32Ty(VMContext), PLoc.getColumn()), }; return llvm::MDNode::get(VMContext, LocMetadata); }
void LogDiagnosticPrinter::HandleDiagnostic(DiagnosticsEngine::Level Level, const Diagnostic &Info) { // Default implementation (Warnings/errors count). DiagnosticConsumer::HandleDiagnostic(Level, Info); // Initialize the main file name, if we haven't already fetched it. if (MainFilename.empty() && Info.hasSourceManager()) { const SourceManager &SM = Info.getSourceManager(); FileID FID = SM.getMainFileID(); if (!FID.isInvalid()) { const FileEntry *FE = SM.getFileEntryForID(FID); if (FE && FE->getName()) MainFilename = FE->getName(); } } // Create the diag entry. DiagEntry DE; DE.DiagnosticID = Info.getID(); DE.DiagnosticLevel = Level; // Format the message. SmallString<100> MessageStr; Info.FormatDiagnostic(MessageStr); DE.Message = MessageStr.str(); // Set the location information. DE.Filename = ""; DE.Line = DE.Column = 0; if (Info.getLocation().isValid() && Info.hasSourceManager()) { const SourceManager &SM = Info.getSourceManager(); PresumedLoc PLoc = SM.getPresumedLoc(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()) DE.Filename = FE->getName(); } } else { DE.Filename = PLoc.getFilename(); DE.Line = PLoc.getLine(); DE.Column = PLoc.getColumn(); } } // Record the diagnostic entry. Entries.push_back(DE); }
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"; }
//--------------------------------------------------------- PresumedLoc DocumentXML::addLocation(const SourceLocation& Loc) { SourceManager& SM = Ctx->getSourceManager(); SourceLocation SpellingLoc = SM.getSpellingLoc(Loc); PresumedLoc PLoc; if (!SpellingLoc.isInvalid()) { PLoc = SM.getPresumedLoc(SpellingLoc); addSourceFileAttribute(PLoc.getFilename()); addAttribute("line", PLoc.getLine()); addAttribute("col", PLoc.getColumn()); } // else there is no error in some cases (eg. CXXThisExpr) return PLoc; }
/// \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 SDiagsWriter::AddLocToRecord(SourceLocation Loc, const SourceManager *SM, PresumedLoc PLoc, RecordDataImpl &Record, unsigned TokSize) { if (PLoc.isInvalid()) { // Emit a "sentinel" location. Record.push_back((unsigned)0); // File. Record.push_back((unsigned)0); // Line. Record.push_back((unsigned)0); // Column. Record.push_back((unsigned)0); // Offset. return; } Record.push_back(getEmitFile(PLoc.getFilename())); Record.push_back(PLoc.getLine()); Record.push_back(PLoc.getColumn()+TokSize); Record.push_back(SM->getFileOffset(Loc)); }
void SourceLocation::print(llvm::raw_ostream &OS, const SourceManager &SM)const{ if (!isValid()) { OS << "<invalid loc>"; return; } if (isFileID()) { PresumedLoc PLoc = SM.getPresumedLoc(*this); // The instantiation and spelling pos is identical for file locs. OS << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); return; } SM.getInstantiationLoc(*this).print(OS, SM); OS << " <Spelling="; SM.getSpellingLoc(*this).print(OS, SM); OS << '>'; }
void CGDebugInfo::EmitStopPoint(llvm::Function *Fn, CGBuilderTy &Builder) { if (CurLoc.isInvalid() || CurLoc.isMacroID()) return; // Don't bother if things are the same as last time. SourceManager &SM = M->getContext().getSourceManager(); if (CurLoc == PrevLoc || (SM.getInstantiationLineNumber(CurLoc) == SM.getInstantiationLineNumber(PrevLoc) && SM.isFromSameFile(CurLoc, PrevLoc))) return; // Update last state. PrevLoc = CurLoc; // Get the appropriate compile unit. llvm::DICompileUnit Unit = getOrCreateCompileUnit(CurLoc); PresumedLoc PLoc = SM.getPresumedLoc(CurLoc); DebugFactory.InsertStopPoint(Unit, PLoc.getLine(), PLoc.getColumn(), Builder.GetInsertBlock()); }
virtual bool VisitObjCMessageExpr(ObjCMessageExpr *E) { if (E->getReceiverKind() == ObjCMessageExpr::Class) { QualType ReceiverType = E->getClassReceiver(); Selector Sel = E->getSelector(); string TypeName = ReceiverType.getAsString(); string SelName = Sel.getAsString(); if (TypeName == "Observer" && SelName == "observerWithTarget:action:") { Expr *Receiver = E->getArg(0)->IgnoreParenCasts(); ObjCSelectorExpr* SelExpr = cast<ObjCSelectorExpr>(E->getArg(1)->IgnoreParenCasts()); Selector Sel = SelExpr->getSelector(); if (const ObjCObjectPointerType *OT = Receiver->getType()->getAs<ObjCObjectPointerType>()) { ObjCInterfaceDecl *decl = OT->getInterfaceDecl(); if (! decl->lookupInstanceMethod(Sel)) { errs() << "Warning: class " << TypeName << " does not implement selector " << Sel.getAsString() << "\n"; SourceLocation Loc = E->getExprLoc(); PresumedLoc PLoc = astContext->getSourceManager().getPresumedLoc(Loc); errs() << "in " << PLoc.getFilename() << " <" << PLoc.getLine() << ":" << PLoc.getColumn() << ">\n"; } } } } return true; }
bool TraverseStmt(Stmt *x) { std::string classname_logendl = "logendl"; // int id = ++_count; // outs() << "BEGIN TraverseStmt [" << id << "]\n"; bool found_interesting_statement_in_this_recursion = false; bool found_first_lessless_of_ilogline = false; if (x != nullptr) { // auto stmt_class_name = x->getStmtClassName(); // outs() << " Stmt ClassName='" << stmt_class_name << "'\n"; // Try to figure out if it's an expression we can determine a type for Expr* expr = nullptr; switch( x->getStmtClass() ) { case Stmt::CXXOperatorCallExprClass: { _output_enabled = true; found_interesting_statement_in_this_recursion = true; //outs() << " Found Expr of interest!\n"; CXXOperatorCallExpr* cxxoper_expr = reinterpret_cast<CXXOperatorCallExpr*>(x); expr = cxxoper_expr; if( cxxoper_expr) { //outs() << " QualType as string: " << get_qual_type_string(cxxoper_expr) << "\n"; if( isLessLessOfILogLine( cxxoper_expr ) ) { if( !_found_logging ) { found_first_lessless_of_ilogline = true; _found_logging = true; //outs() << " Found logging!\n"; } if (found_first_lessless_of_ilogline && isLessLessOnLogEndl(cxxoper_expr)) { _found_endl_at_end = true; //outs() << " Found endl at end!\n"; } } } } break; default: break; } } //outs() << "DIVE TraverseStmt [" << id << "]\n"; ++_depth; RecursiveASTVisitor<FindNamedClassVisitor>::TraverseStmt(x); --_depth; //outs() << "END TraverseStmt [" << id << "]\n"; if( found_interesting_statement_in_this_recursion ) { if( _found_logging && !_found_endl_at_end ) { /* if( outs().has_colors() ) { outs().changeColor(raw_ostream::RED); } */ FullSourceLoc FullLocation = Context->getFullLoc(x->getLocStart()); SourceManager& SourceMgr = Context->getSourceManager(); PresumedLoc pLoc = SourceMgr.getPresumedLoc( FullLocation ); outs() << "ERROR on " << pLoc.getFilename() << " " << pLoc.getLine() << ":" << pLoc.getColumn() << ": Found statement in which the logger is used, but endl isn't at the end\n"; /* if( outs().has_colors() ) { outs().changeColor(raw_ostream::WHITE, false); } */ } reset_after_recusion_into_interesting(); } return true; }
unsigned Line(SourceLocation const& l, SourceManager const& sm) { PresumedLoc pl = sm.getPresumedLoc(l); return pl.getLine(); }
void TypePrinter::PrintTag(TagDecl *D, std::string &InnerString) { if (Policy.SuppressTag) return; std::string Buffer; bool HasKindDecoration = false; // We don't print tags unless this is an elaborated type. // In C, we just assume every RecordType is an elaborated type. if (!Policy.LangOpts.CPlusPlus && !D->getTypedefForAnonDecl()) { HasKindDecoration = true; Buffer += D->getKindName(); Buffer += ' '; } if (!Policy.SuppressScope) // Compute the full nested-name-specifier for this type. In C, // this will always be empty. AppendScope(D->getDeclContext(), Buffer); if (const IdentifierInfo *II = D->getIdentifier()) Buffer += II->getNameStart(); else if (TypedefDecl *Typedef = D->getTypedefForAnonDecl()) { assert(Typedef->getIdentifier() && "Typedef without identifier?"); Buffer += Typedef->getIdentifier()->getNameStart(); } else { // Make an unambiguous representation for anonymous types, e.g. // <anonymous enum at /usr/include/string.h:120:9> llvm::raw_string_ostream OS(Buffer); OS << "<anonymous"; if (Policy.AnonymousTagLocations) { // Suppress the redundant tag keyword if we just printed one. // We don't have to worry about ElaboratedTypes here because you can't // refer to an anonymous type with one. if (!HasKindDecoration) OS << " " << D->getKindName(); if (D->getLocation().isValid()) { PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc( D->getLocation()); OS << " at " << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); } } OS << '>'; } // If this is a class template specialization, print the template // arguments. if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) { const TemplateArgument *Args; unsigned NumArgs; if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(TAW->getType()); Args = TST->getArgs(); NumArgs = TST->getNumArgs(); } else { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); Args = TemplateArgs.getFlatArgumentList(); NumArgs = TemplateArgs.flat_size(); } Buffer += TemplateSpecializationType::PrintTemplateArgumentList(Args, NumArgs, Policy); } if (!InnerString.empty()) { Buffer += ' '; Buffer += InnerString; } std::swap(Buffer, InnerString); }
/// 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 TypePrinter::printTag(TagDecl *D, raw_ostream &OS) { if (Policy.SuppressTag) return; bool HasKindDecoration = false; // bool SuppressTagKeyword // = Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword; // We don't print tags unless this is an elaborated type. // In C, we just assume every RecordType is an elaborated type. if (!(Policy.LangOpts.CPlusPlus || Policy.SuppressTagKeyword || D->getTypedefNameForAnonDecl())) { HasKindDecoration = true; OS << D->getKindName(); OS << ' '; } // Compute the full nested-name-specifier for this type. // In C, this will always be empty except when the type // being printed is anonymous within other Record. if (!Policy.SuppressScope) AppendScope(D->getDeclContext(), OS); if (const IdentifierInfo *II = D->getIdentifier()) OS << II->getName(); else if (TypedefNameDecl *Typedef = D->getTypedefNameForAnonDecl()) { assert(Typedef->getIdentifier() && "Typedef without identifier?"); OS << Typedef->getIdentifier()->getName(); } else { // Make an unambiguous representation for anonymous types, e.g. // <anonymous enum at /usr/include/string.h:120:9> if (isa<CXXRecordDecl>(D) && cast<CXXRecordDecl>(D)->isLambda()) { OS << "<lambda"; HasKindDecoration = true; } else { OS << "<anonymous"; } if (Policy.AnonymousTagLocations) { // Suppress the redundant tag keyword if we just printed one. // We don't have to worry about ElaboratedTypes here because you can't // refer to an anonymous type with one. if (!HasKindDecoration) OS << " " << D->getKindName(); PresumedLoc PLoc = D->getASTContext().getSourceManager().getPresumedLoc( D->getLocation()); if (PLoc.isValid()) { OS << " at " << PLoc.getFilename() << ':' << PLoc.getLine() << ':' << PLoc.getColumn(); } } OS << '>'; } // If this is a class template specialization, print the template // arguments. if (ClassTemplateSpecializationDecl *Spec = dyn_cast<ClassTemplateSpecializationDecl>(D)) { const TemplateArgument *Args; unsigned NumArgs; if (TypeSourceInfo *TAW = Spec->getTypeAsWritten()) { const TemplateSpecializationType *TST = cast<TemplateSpecializationType>(TAW->getType()); Args = TST->getArgs(); NumArgs = TST->getNumArgs(); } else { const TemplateArgumentList &TemplateArgs = Spec->getTemplateArgs(); Args = TemplateArgs.data(); NumArgs = TemplateArgs.size(); } IncludeStrongLifetimeRAII Strong(Policy); TemplateSpecializationType::PrintTemplateArgumentList(OS, Args, NumArgs, Policy); } spaceBeforePlaceHolder(OS); }
void AnalyzerStatsChecker::checkEndAnalysis(ExplodedGraph &G, BugReporter &B, ExprEngine &Eng) const { const CFG *C = 0; const SourceManager &SM = B.getSourceManager(); llvm::SmallPtrSet<const CFGBlock*, 256> reachable; // Root node should have the location context of the top most function. const ExplodedNode *GraphRoot = *G.roots_begin(); const LocationContext *LC = GraphRoot->getLocation().getLocationContext(); const Decl *D = LC->getDecl(); // Iterate over the exploded graph. for (ExplodedGraph::node_iterator I = G.nodes_begin(); I != G.nodes_end(); ++I) { const ProgramPoint &P = I->getLocation(); // Only check the coverage in the top level function (optimization). if (D != P.getLocationContext()->getDecl()) continue; if (const BlockEntrance *BE = dyn_cast<BlockEntrance>(&P)) { const CFGBlock *CB = BE->getBlock(); reachable.insert(CB); } } // Get the CFG and the Decl of this block. C = LC->getCFG(); unsigned total = 0, unreachable = 0; // Find CFGBlocks that were not covered by any node for (CFG::const_iterator I = C->begin(); I != C->end(); ++I) { const CFGBlock *CB = *I; ++total; // Check if the block is unreachable if (!reachable.count(CB)) { ++unreachable; } } // We never 'reach' the entry block, so correct the unreachable count unreachable--; // There is no BlockEntrance corresponding to the exit block as well, so // assume it is reached as well. unreachable--; // Generate the warning string SmallString<128> buf; llvm::raw_svector_ostream output(buf); PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); if (!Loc.isValid()) return; if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { const NamedDecl *ND = cast<NamedDecl>(D); output << *ND; } else if (isa<BlockDecl>(D)) { output << "block(line:" << Loc.getLine() << ":col:" << Loc.getColumn(); } NumBlocksUnreachable += unreachable; NumBlocks += total; std::string NameOfRootFunction = output.str(); output << " -> Total CFGBlocks: " << total << " | Unreachable CFGBlocks: " << unreachable << " | Exhausted Block: " << (Eng.wasBlocksExhausted() ? "yes" : "no") << " | Empty WorkList: " << (Eng.hasEmptyWorkList() ? "yes" : "no"); B.EmitBasicReport(D, "Analyzer Statistics", "Internal Statistics", output.str(), PathDiagnosticLocation(D, SM)); // Emit warning for each block we bailed out on. typedef CoreEngine::BlocksExhausted::const_iterator ExhaustedIterator; const CoreEngine &CE = Eng.getCoreEngine(); for (ExhaustedIterator I = CE.blocks_exhausted_begin(), E = CE.blocks_exhausted_end(); I != E; ++I) { const BlockEdge &BE = I->first; const CFGBlock *Exit = BE.getDst(); const CFGElement &CE = Exit->front(); if (const CFGStmt *CS = dyn_cast<CFGStmt>(&CE)) { SmallString<128> bufI; llvm::raw_svector_ostream outputI(bufI); outputI << "(" << NameOfRootFunction << ")" << ": The analyzer generated a sink at this point"; B.EmitBasicReport(D, "Sink Point", "Internal Statistics", outputI.str(), PathDiagnosticLocation::createBegin(CS->getStmt(), SM, LC)); } } }
/// 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()); }
/// \brief Print out the file/line/column information and include trace. /// /// This method handlen the emission of the diagnostic location information. /// This includes extracting as much location information as is present for /// the diagnostic and printing it, as well as any include stack or source /// ranges necessary. void TextDiagnostic::emitDiagnosticLoc(SourceLocation Loc, PresumedLoc PLoc, DiagnosticsEngine::Level Level, ArrayRef<CharSourceRange> Ranges, const SourceManager &SM) { if (PLoc.isInvalid()) { // At least print the file name if available: FileID FID = SM.getFileID(Loc); 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 << ": "; } } return; } unsigned LineNo = PLoc.getLine(); if (!DiagOpts->ShowLocation) return; if (DiagOpts->ShowColors) OS.changeColor(savedColor, true); OS << PLoc.getFilename(); switch (DiagOpts->getFormat()) { case DiagnosticOptions::LFort: OS << ':' << LineNo; break; case DiagnosticOptions::Msvc: OS << '(' << LineNo; break; case DiagnosticOptions::Vi: OS << " +" << LineNo; break; } if (DiagOpts->ShowColumn) // Compute the column number. if (unsigned ColNo = PLoc.getColumn()) { if (DiagOpts->getFormat() == DiagnosticOptions::Msvc) { OS << ','; ColNo--; } else OS << ':'; OS << ColNo; } switch (DiagOpts->getFormat()) { case DiagnosticOptions::LFort: case DiagnosticOptions::Vi: OS << ':'; break; case DiagnosticOptions::Msvc: OS << ") : "; break; } if (DiagOpts->ShowSourceRanges && !Ranges.empty()) { FileID CaretFileID = SM.getFileID(SM.getExpansionLoc(Loc)); bool PrintedRange = false; for (ArrayRef<CharSourceRange>::const_iterator RI = Ranges.begin(), RE = Ranges.end(); RI != RE; ++RI) { // Ignore invalid ranges. if (!RI->isValid()) continue; SourceLocation B = SM.getExpansionLoc(RI->getBegin()); SourceLocation E = SM.getExpansionLoc(RI->getEnd()); // 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 && RI->getEnd().isMacroID()) E = SM.getExpansionRange(RI->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 (RI->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 << ' '; }
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(); } }
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(); }