Index: include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h =================================================================== --- include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h +++ include/clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h @@ -126,6 +126,36 @@ AnalysisDeclContext *getAnalysisDeclContext(const Decl *D) { return AnaCtxMgr.getContext(D); } + + static bool isInCodeFile(SourceLocation SL, const SourceManager &SM) { + if (SM.isInMainFile(SL)) + return true; + + // Support the "unified sources" compilation method (eg. WebKit) that + // involves producing non-header files that include other non-header files. + // We should be included directly from a UnifiedSource* file + // and we shouldn't be a header - which is a very safe defensive check. + SourceLocation IL = SM.getIncludeLoc(SM.getFileID(SL)); + if (!IL.isValid() || !SM.isInMainFile(IL)) + return false; + // Should rather be "file name starts with", but the current .getFilename + // includes the full path. + if (SM.getFilename(IL).contains("UnifiedSource")) { + StringRef Name = SM.getFilename(SL); + if (Name.endswith_lower(".c") || Name.endswith_lower(".cpp") || + Name.endswith_lower(".cc") || Name.endswith_lower(".m") || + Name.endswith_lower(".mm")) { + return true; + } + } + + return false; + } + + bool isInCodeFile(SourceLocation SL) { + const SourceManager &SM = getASTContext().getSourceManager(); + return isInCodeFile(SL, SM); + } }; } // enAnaCtxMgrspace Index: lib/StaticAnalyzer/Core/CallEvent.cpp =================================================================== --- lib/StaticAnalyzer/Core/CallEvent.cpp +++ lib/StaticAnalyzer/Core/CallEvent.cpp @@ -938,15 +938,15 @@ bool ObjCMethodCall::canBeOverridenInSubclass(ObjCInterfaceDecl *IDecl, Selector Sel) const { assert(IDecl); - const SourceManager &SM = - getState()->getStateManager().getContext().getSourceManager(); - // If the class interface is declared inside the main file, assume it is not // subcassed. // TODO: It could actually be subclassed if the subclass is private as well. // This is probably very rare. SourceLocation InterfLoc = IDecl->getEndOfDefinitionLoc(); - if (InterfLoc.isValid() && SM.isInMainFile(InterfLoc)) + if (InterfLoc.isValid() && getState()->getStateManager() + .getOwningEngine() + ->getAnalysisManager() + .isInCodeFile(InterfLoc)) return false; // Assume that property accessors are not overridden. @@ -968,7 +968,11 @@ return false; // If outside the main file, - if (D->getLocation().isValid() && !SM.isInMainFile(D->getLocation())) + if (D->getLocation().isValid() && !getState() + ->getStateManager() + .getOwningEngine() + ->getAnalysisManager() + .isInCodeFile(D->getLocation())) return true; if (D->isOverriding()) { Index: lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp =================================================================== --- lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -806,8 +806,9 @@ /// This checks static properties of the function, such as its signature and /// CFG, to determine whether the analyzer should ever consider inlining it, /// in any context. -static bool mayInlineDecl(AnalysisDeclContext *CalleeADC, - AnalyzerOptions &Opts) { +static bool mayInlineDecl(AnalysisManager &AMgr, + AnalysisDeclContext *CalleeADC) { + AnalyzerOptions &Opts = AMgr.getAnalyzerOptions(); // FIXME: Do not inline variadic calls. if (CallEvent::isVariadic(CalleeADC->getDecl())) return false; @@ -830,7 +831,7 @@ // Conditionally control the inlining of methods on objects that look // like C++ containers. if (!Opts.mayInlineCXXContainerMethods()) - if (!Ctx.getSourceManager().isInMainFile(FD->getLocation())) + if (!AMgr.isInCodeFile(FD->getLocation())) if (isContainerMethod(Ctx, FD)) return false; @@ -891,7 +892,7 @@ } else { // We haven't actually checked the static properties of this function yet. // Do that now, and record our decision in the function summaries. - if (mayInlineDecl(CalleeADC, Opts)) { + if (mayInlineDecl(getAnalysisManager(), CalleeADC)) { Engine.FunctionSummaries->markMayInline(D); } else { Engine.FunctionSummaries->markShouldNotInline(D); Index: lib/StaticAnalyzer/Core/PathDiagnostic.cpp =================================================================== --- lib/StaticAnalyzer/Core/PathDiagnostic.cpp +++ lib/StaticAnalyzer/Core/PathDiagnostic.cpp @@ -29,6 +29,7 @@ #include "clang/Basic/LLVM.h" #include "clang/Basic/SourceLocation.h" #include "clang/Basic/SourceManager.h" +#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExplodedGraph.h" #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h" #include "llvm/ADT/ArrayRef.h" @@ -148,11 +149,11 @@ if (CallLoc.isMacroID()) return nullptr; - assert(SMgr.isInMainFile(CallLoc) && + assert(AnalysisManager::isInCodeFile(CallLoc, SMgr) && "The call piece should be in the main file."); // Check if CP represents a path through a function outside of the main file. - if (!SMgr.isInMainFile(CP->callEnterWithin.asLocation())) + if (!AnalysisManager::isInCodeFile(CP->callEnterWithin.asLocation(), SMgr)) return CP; const PathPieces &Path = CP->path; Index: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp =================================================================== --- lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp +++ lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp @@ -678,7 +678,7 @@ SourceLocation SL = Body ? Body->getLocStart() : D->getLocation(); SL = SM.getExpansionLoc(SL); - if (!Opts->AnalyzeAll && !SM.isWrittenInMainFile(SL)) { + if (!Opts->AnalyzeAll && !Mgr->isInCodeFile(SL)) { if (SL.isInvalid() || SM.isInSystemHeader(SL)) return AM_None; return Mode & ~AM_Path; Index: test/Analysis/unified-sources/UnifiedSource-1.cpp =================================================================== --- /dev/null +++ test/Analysis/unified-sources/UnifiedSource-1.cpp @@ -0,0 +1,5 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=core -verify %s + +// There should still be diagnostics within included files. +#include "source1.cpp" +#include "source2.cpp" Index: test/Analysis/unified-sources/source1.cpp =================================================================== --- /dev/null +++ test/Analysis/unified-sources/source1.cpp @@ -0,0 +1,6 @@ +// RUN: true + +int foo(int x) { + if (x) {} + return 1 / x; // expected-warning{{}} +} Index: test/Analysis/unified-sources/source2.cpp =================================================================== --- /dev/null +++ test/Analysis/unified-sources/source2.cpp @@ -0,0 +1,6 @@ +// RUN: true + +int bar() { + int *x = 0; + return *x; // expected-warning{{}} +}