#include "clang/Basic/SourceManager.h"
#include "clang/Basic/Version.h"
#include "clang/CrossTU/CrossTranslationUnit.h"
+#include "clang/Frontend/ASTUnit.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Lex/TokenConcatenation.h"
#include "clang/Rewrite/Core/HTMLRewrite.h"
const FIDMap& FM;
AnalyzerOptions &AnOpts;
const Preprocessor &PP;
+ const cross_tu::CrossTranslationUnitContext &CTU;
llvm::SmallVector<const PathDiagnosticMacroPiece *, 0> MacroPieces;
public:
PlistPrinter(const FIDMap& FM, AnalyzerOptions &AnOpts,
- const Preprocessor &PP)
- : FM(FM), AnOpts(AnOpts), PP(PP) {
+ const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU)
+ : FM(FM), AnOpts(AnOpts), PP(PP), CTU(CTU) {
}
void ReportDiag(raw_ostream &o, const PathDiagnosticPiece& P) {
} // end of anonymous namespace
static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
- AnalyzerOptions &AnOpts,
- const Preprocessor &PP,
+ AnalyzerOptions &AnOpts, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU,
const PathPieces &Path);
/// Print coverage information to output stream {@code o}.
FIDMap &FM,
llvm::raw_fd_ostream &o);
-static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
- const Preprocessor &PP);
+static ExpansionInfo
+getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU);
//===----------------------------------------------------------------------===//
// Methods of PlistPrinter.
for (const PathDiagnosticMacroPiece *P : MacroPieces) {
const SourceManager &SM = PP.getSourceManager();
- ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP);
+ ExpansionInfo EI = getExpandedMacro(P->getLocation().asLocation(), PP, CTU);
Indent(o, indent) << "<dict>\n";
++indent;
}
static void printBugPath(llvm::raw_ostream &o, const FIDMap& FM,
- AnalyzerOptions &AnOpts,
- const Preprocessor &PP,
+ AnalyzerOptions &AnOpts, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU,
const PathPieces &Path) {
- PlistPrinter Printer(FM, AnOpts, PP);
+ PlistPrinter Printer(FM, AnOpts, PP, CTU);
assert(std::is_partitioned(
Path.begin(), Path.end(),
[](const std::shared_ptr<PathDiagnosticPiece> &E)
o << " <dict>\n";
const PathDiagnostic *D = *DI;
- printBugPath(o, FM, AnOpts, PP, D->path);
+ printBugPath(o, FM, AnOpts, PP, CTU, D->path);
// Output the bug type and bug category.
o << " <key>description</key>";
// Definitions of helper functions and methods for expanding macros.
//===----------------------------------------------------------------------===//
-static ExpansionInfo getExpandedMacro(SourceLocation MacroLoc,
- const Preprocessor &PP) {
+static ExpansionInfo
+getExpandedMacro(SourceLocation MacroLoc, const Preprocessor &PP,
+ const cross_tu::CrossTranslationUnitContext &CTU) {
+
+ const Preprocessor *PPToUse = &PP;
+ if (auto LocAndUnit = CTU.getImportedFromSourceLocation(MacroLoc)) {
+ MacroLoc = LocAndUnit->first;
+ PPToUse = &LocAndUnit->second->getPreprocessor();
+ }
llvm::SmallString<200> ExpansionBuf;
llvm::raw_svector_ostream OS(ExpansionBuf);
- TokenPrinter Printer(OS, PP);
+ TokenPrinter Printer(OS, *PPToUse);
llvm::SmallPtrSet<IdentifierInfo*, 8> AlreadyProcessedTokens;
- std::string MacroName =
- getMacroNameAndPrintExpansion(Printer, MacroLoc, PP, MacroArgMap{},
- AlreadyProcessedTokens);
+ std::string MacroName = getMacroNameAndPrintExpansion(
+ Printer, MacroLoc, *PPToUse, MacroArgMap{}, AlreadyProcessedTokens);
return { MacroName, OS.str() };
}
--- /dev/null
+// RUN: rm -rf %t && mkdir %t
+// RUN: mkdir -p %t/ctudir
+// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu \
+// RUN: -emit-pch -o %t/ctudir/plist-macros-ctu.c.ast %S/Inputs/plist-macros-ctu.c
+// RUN: cp %S/Inputs/plist-macros-with-expansion-ctu.c.externalDefMap.txt %t/ctudir/externalDefMap.txt
+
+// RUN: %clang_analyze_cc1 -analyzer-checker=core \
+// RUN: -analyzer-config experimental-enable-naive-ctu-analysis=true \
+// RUN: -analyzer-config ctu-dir=%t/ctudir \
+// RUN: -analyzer-config expand-macros=true \
+// RUN: -analyzer-output=plist-multi-file -o %t.plist -verify %s
+
+// Check the macro expansions from the plist output here, to make the test more
+// understandable.
+// RUN: FileCheck --input-file=%t.plist %s
+
+extern void F1(int **);
+extern void F2(int **);
+extern void F3(int **);
+extern void F_H(int **);
+
+void test0() {
+ int *X;
+ F3(&X);
+ *X = 1; // expected-warning{{Dereference of null pointer}}
+}
+// CHECK: <key>name</key><string>M1</string>
+// CHECK-NEXT: <key>expansion</key><string>*Z = (int *)0</string>
+
+
+void test1() {
+ int *X;
+ F1(&X);
+ *X = 1; // expected-warning{{Dereference of null pointer}}
+}
+// CHECK: <key>name</key><string>M</string>
+// CHECK-NEXT: <key>expansion</key><string>*X = (int *)0</string>
+
+void test2() {
+ int *X;
+ F2(&X);
+ *X = 1; // expected-warning{{Dereference of null pointer}}
+}
+// CHECK: <key>name</key><string>M</string>
+// CHECK-NEXT: <key>expansion</key><string>*Y = (int *)0</string>
+
+#define M F1(&X)
+
+void test3() {
+ int *X;
+ M;
+ *X = 1; // expected-warning{{Dereference of null pointer}}
+}
+// CHECK: <key>name</key><string>M</string>
+// CHECK-NEXT: <key>expansion</key><string>F1(&X)</string>
+// CHECK: <key>name</key><string>M</string>
+// CHECK-NEXT: <key>expansion</key><string>*X = (int *)0</string>
+
+#undef M
+#define M F2(&X)
+
+void test4() {
+ int *X;
+ M;
+ *X = 1; // expected-warning{{Dereference of null pointer}}
+}
+
+// CHECK: <key>name</key><string>M</string>
+// CHECK-NEXT: <key>expansion</key><string>F2(&X)</string>
+// CHECK: <key>name</key><string>M</string>
+// CHECK-NEXT: <key>expansion</key><string>*Y = (int *)0</string>
+
+void test_h() {
+ int *X;
+ F_H(&X);
+ *X = 1; // expected-warning{{Dereference of null pointer}}
+}
+
+// CHECK: <key>name</key><string>M_H</string>
+// CHECK-NEXT: <key>expansion</key><string>*A = (int *)0</string>