Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -1683,15 +1683,51 @@ return nullptr; } + //get the file buffer + FileID FileID = SourceMgr.getFileID(Loc); + llvm::MemoryBuffer* FileBuf = SourceMgr.getBuffer(FileID); + SourceLocation LastIncludeLoc = SourceMgr.getLocForStartOfFile(FileID); + + //Find the Location of the last #include directive in the file + Lexer IncludeLexer(FileID,FileBuf,SourceMgr,LangOpts); + while (1) { + Token Tok; + IncludeLexer.LexFromRawLexer(Tok); + if (Tok.is(tok::eof)) + break; + if (Tok.is(tok::hash)){ + IncludeLexer.LexFromRawLexer(Tok); + if(Tok.getRawIdentifier() == "include" && Tok.getLocation().isValid()) + LastIncludeLoc = Tok.getLocation(); + } + } + + + //Get the location of the line after the last #include directive + PresumedLoc PLoc = SourceMgr.getPresumedLoc(LastIncludeLoc); + SourceLocation FixitLoc = SourceMgr.translateLineCol(FileID,PLoc.getLine()+1,PLoc.getColumn()); + if (FixitLoc.isInvalid()){ + FixitLoc = LastIncludeLoc; + } + + + if (!ForRedeclaration && Context.BuiltinInfo.isPredefinedLibFunction(ID)) { Diag(Loc, diag::ext_implicit_lib_function_decl) << Context.BuiltinInfo.GetName(ID) << R; + //Build 'insert missing header' string + std::string FixitString = "#include <"; + FixitString.append(Context.BuiltinInfo.getHeaderName(ID)); + FixitString.append(">"); + StringRef FixitStringRef(FixitString.c_str()); + if (Context.BuiltinInfo.getHeaderName(ID) && !Diags.isIgnored(diag::ext_implicit_lib_function_decl, Loc)) - Diag(Loc, diag::note_include_header_or_declare) + Diag(FixitLoc, diag::note_include_header_or_declare) << Context.BuiltinInfo.getHeaderName(ID) - << Context.BuiltinInfo.GetName(ID); + << Context.BuiltinInfo.GetName(ID) + << FixItHint::CreateInsertion(FixitLoc, FixitStringRef); } DeclContext *Parent = Context.getTranslationUnitDecl(); Index: test/Sema/Inputs/dummyheader.h =================================================================== --- /dev/null +++ test/Sema/Inputs/dummyheader.h @@ -0,0 +1 @@ +//this is a dummy header used by implicit-builtin-include-fixit.c Index: test/Sema/implicit-builtin-decl.c =================================================================== --- test/Sema/implicit-builtin-decl.c +++ test/Sema/implicit-builtin-decl.c @@ -3,7 +3,7 @@ void f() { int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring library function 'malloc' with type}} \ - // expected-note{{include the header or explicitly provide a declaration for 'malloc'}} \ + // expected-note@-3{{include the header or explicitly provide a declaration for 'malloc'}} \ // expected-note{{'malloc' is a builtin with type 'void *}} } Index: test/Sema/implicit-builtin-include-fixit.c =================================================================== --- /dev/null +++ test/Sema/implicit-builtin-include-fixit.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -Wdocumentation -fdiagnostics-parseable-fixits %s 2>&1 | FileCheck %s + +#include "Inputs/dummyheader.h"/*dummy header to test implicit declaration fixit*/ + +void f() { + int *ptr = malloc(sizeof(int) * 10); // expected-warning{{implicitly declaring library function 'malloc' with type}}\ + // expected-note@-2{{include the header or explicitly provide a declaration for 'malloc'}} + // CHECK: fix-it:"{{.*}}":{[[@LINE-4]]:1-[[@LINE-4]]:1}:"#include " +}